Blender V5.0
area.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
8
10
12
13/* Importance sampling.
14 *
15 * An Area-Preserving Parametrization for Spherical Rectangles.
16 * Carlos Urena et al.
17 *
18 * NOTE: light_p is modified when sample_coord is true. */
20 ccl_private float3 *light_p,
21 const float3 axis_u,
22 const float len_u,
23 const float3 axis_v,
24 const float len_v,
25 const float2 rand,
26 bool sample_coord)
27{
28 /* Compute local reference system R. */
29 const float3 x = axis_u;
30 const float3 y = axis_v;
31 float3 z = cross(x, y);
32 /* Compute rectangle coords in local reference system. */
33 const float3 dir = *light_p - P;
34 float z0 = dot(dir, z);
35 /* Flip 'z' to make it point against Q. */
36 if (z0 > 0.0f) {
37 z *= -1.0f;
38 z0 *= -1.0f;
39 }
40 const float xc = dot(dir, x);
41 const float yc = dot(dir, y);
42 const float x0 = xc - 0.5f * len_u;
43 const float x1 = xc + 0.5f * len_u;
44 const float y0 = yc - 0.5f * len_v;
45 const float y1 = yc + 0.5f * len_v;
46 /* Compute predefined constants. */
47 float4 nz = make_float4(-y0, x1, y1, -x0);
48 nz /= sqrt(nz * nz + z0 * z0);
49 /* The original paper uses `acos()` to compute the internal angles here, and then computes the
50 * solid angle as their sum minus 2*pi. However, for very small rectangles, this results in
51 * excessive cancellation error since the sum will be almost 2*pi as well.
52 * This can be avoided by using that `asin(x) = pi/2 - acos(x)`. */
53 const float g0 = safe_asinf(-nz.x * nz.y);
54 const float g1 = safe_asinf(-nz.y * nz.z);
55 const float g2 = safe_asinf(-nz.z * nz.w);
56 const float g3 = safe_asinf(-nz.w * nz.x);
57 const float S = -(g0 + g1 + g2 + g3);
58
59 if (sample_coord) {
60 /* Compute predefined constants. */
61 const float b0 = nz.x;
62 const float b1 = nz.z;
63 const float b0sq = b0 * b0;
64 /* Compute cu.
65 * In the original paper, an additional constant k is involved here. However, just like above,
66 * it causes cancellation issues. The same `asin()` terms from above can be used instead, and
67 * the extra +pi that would remain in the expression for au can be removed by flipping the sign
68 * of cos(au) and sin(au), which also cancels if we flip the sign of b1 in the fu term. */
69 const float au = rand.x * S + g2 + g3;
70 const float fu = safe_divide(cosf(au) * b0 + b1, sinf(au));
71 float cu = copysignf(1.0f / sqrtf(fu * fu + b0sq), fu);
72 cu = clamp(cu, -1.0f, 1.0f);
73 /* Compute xu. */
74 float xu = -(cu * z0) / max(sqrtf(1.0f - cu * cu), 1e-7f);
75 xu = clamp(xu, x0, x1);
76 /* Compute yv. */
77 const float d2 = sqr(xu) + sqr(z0);
78 const float h0 = y0 / sqrtf(d2 + sqr(y0));
79 const float h1 = y1 / sqrtf(d2 + sqr(y1));
80 const float hv = h0 + rand.y * (h1 - h0);
81 const float hv2 = hv * hv;
82 const float yv = (hv2 < 1.0f - 1e-6f) ? hv * sqrtf(d2 / (1.0f - hv2)) : y1;
83
84 /* Transform (xu, yv, z0) to world coords. */
85 *light_p = P + xu * x + yv * y + z0 * z;
86 }
87
88 /* return pdf */
89 if (S < 1e-5f || reduce_min(sqr(nz)) > 0.99999f) {
90 /* The solid angle is too small to be computed accurately in single precision.
91 * As a fallback, approximate it using the planar sampling PDF,
92 * for such tiny lights the difference is irrelevant.
93 *
94 * A threshold of 1e-5 was found to be the smallest option that avoids structured
95 * artifacts at all tested parameter combinations. The additional check of nz is
96 * needed for the case where the light is viewed from grazing angles, see e.g. #98930.
97 */
98 const float t = len(dir);
99 return safe_divide(-t * t * t, (z0 * len_u * len_v));
100 }
101 return 1.0f / S;
102}
103
104/* Light spread. */
105
107 const float3 lightNg,
108 const float tan_half_spread,
109 const float normalize_spread)
110{
111 /* Model a soft-box grid, computing the ratio of light not hidden by the
112 * slats of the grid at a given angle. (see D10594). */
113 const float tan_a = tan_angle(-D, lightNg);
114
115 if (tan_half_spread == 0.0f) {
116 /* The factor M_PI_F comes from integrating the radiance over the hemisphere */
117 return (tan_a > 1e-5f) ? 0.0f : M_PI_F;
118 }
119
120 return max((tan_half_spread - tan_a) * normalize_spread, 0.0f);
121}
122
123/* Compute the minimal rectangle, circle or ellipse that covers the valid sample region, to reduce
124 * noise with low spread. */
126 const float3 lightNg,
127 ccl_private float3 *lightP,
128 ccl_private float3 *axis_u,
129 ccl_private float *len_u,
130 ccl_private float3 *axis_v,
131 ccl_private float *len_v,
132 const float tan_half_spread,
133 ccl_private bool *sample_rectangle)
134{
135 /* Distance from shading point to area light plane and the closest point on that plane. */
136 const float t = dot(lightNg, P - *lightP);
137 const float3 closest_P = P - t * lightNg;
138
139 /* Radius of circle on area light that actually affects the shading point. */
140 const float r_spread = t * tan_half_spread;
141
142 /* Local uv coordinates of closest point. */
143 const float spread_u = dot(*axis_u, closest_P - *lightP);
144 const float spread_v = dot(*axis_v, closest_P - *lightP);
145
146 const bool is_round = !(*sample_rectangle) && (*len_u == *len_v);
147
148 /* Whether we should sample the spread circle. */
149 bool sample_spread = (r_spread == 0.0f);
150 if (is_round && !sample_spread) {
151 /* Distance between the centers of the disk light and the valid region circle. */
152 const float dist = len(make_float2(spread_u, spread_v));
153
154 /* Radius of the disk light. */
155 const float r = *len_u * 0.5f;
156
157 if (dist >= r + r_spread) {
158 /* Two circles are outside each other or touch externally. */
159 return false;
160 }
161
162 sample_spread = (dist <= fabsf(r - r_spread)) && (r_spread < r);
163 if (dist > fabsf(r - r_spread)) {
164 /* Two circles intersect. Find the smallest rectangle that covers the intersection */
165 const float len_u_ = r + r_spread - dist;
166 const float len_v_ = (fabsf(sqr(r) - sqr(r_spread)) >= sqr(dist)) ?
167 2.0f * fminf(r, r_spread) :
168 sqrtf(sqr(2.0f * r_spread) -
169 sqr(dist + (sqr(r_spread) - sqr(r)) / dist));
170
171 const float rect_area = len_u_ * len_v_;
172 const float circle_area = M_PI_F * sqr(r);
173 const float spread_area = M_PI_F * sqr(r_spread);
174
175 /* Sample the shape with minimal area. */
176 if (rect_area < fminf(circle_area, spread_area)) {
177 *sample_rectangle = true;
178 *axis_u = normalize(*lightP - closest_P);
179 *axis_v = rotate_around_axis(*axis_u, lightNg, M_PI_2_F);
180 *len_u = len_u_;
181 *len_v = len_v_;
182 *lightP = 0.5f * (*lightP + closest_P + *axis_u * (r_spread - r));
183 return true;
184 }
185
186 sample_spread = (spread_area < circle_area);
187 }
188 }
189 else if (!is_round && !sample_spread) {
190 /* Compute rectangle encompassing the circle that affects the shading point,
191 * clamped to the bounds of the area light. */
192 const float min_u = max(spread_u - r_spread, -*len_u * 0.5f);
193 const float max_u = min(spread_u + r_spread, *len_u * 0.5f);
194 const float min_v = max(spread_v - r_spread, -*len_v * 0.5f);
195 const float max_v = min(spread_v + r_spread, *len_v * 0.5f);
196
197 /* Skip if rectangle is empty. */
198 if (min_u >= max_u || min_v >= max_v) {
199 return false;
200 }
201
202 const float rect_len_u = max_u - min_u;
203 const float rect_len_v = max_v - min_v;
204
205 const float rect_area = rect_len_u * rect_len_v;
206 const float ellipse_area = (*sample_rectangle) ? FLT_MAX : M_PI_4_F * (*len_u) * (*len_v);
207 const float spread_area = M_PI_F * sqr(r_spread);
208
209 /* Sample the shape with minimal area. */
210 /* NOTE: we don't switch to spread circle sampling for rectangle light because rectangle light
211 * supports solid angle sampling, which has less variance than sampling the area. If ellipse
212 * area light also supports solid angle sampling, `*sample_rectangle ||` could be deleted. */
213 if (*sample_rectangle || rect_area < fminf(ellipse_area, spread_area)) {
214 *sample_rectangle = true;
215
216 /* Compute new area light center position and axes from rectangle in local
217 * uv coordinates. */
218 const float new_center_u = 0.5f * (min_u + max_u);
219 const float new_center_v = 0.5f * (min_v + max_v);
220
221 *len_u = rect_len_u;
222 *len_v = rect_len_v;
223 *lightP = *lightP + *axis_u * new_center_u + *axis_v * new_center_v;
224 return true;
225 }
226 *sample_rectangle = false;
227 sample_spread = (spread_area < ellipse_area);
228 }
229
230 if (sample_spread) {
231 *sample_rectangle = false;
232 *lightP = *lightP + *axis_u * spread_u + *axis_v * spread_v;
233 *len_u = r_spread * 2.0f;
234 *len_v = r_spread * 2.0f;
235 return true;
236 }
237
238 /* Don't clamp. */
239 return true;
240}
241
243{
244 return light->invarea < 0.0f;
245}
246
247/* Common API. */
248/* Compute `eval_fac` and `pdf`. Also sample a new position on the light if `sample_coord`. */
249template<bool in_volume_segment>
251 const float3 ray_P,
252 ccl_private float3 *light_P,
254 const float2 rand,
255 bool sample_coord)
256{
257 float3 axis_u = klight->area.axis_u;
258 float3 axis_v = klight->area.axis_v;
259 float len_u = klight->area.len_u;
260 float len_v = klight->area.len_v;
261
262 const float3 Ng = klight->area.dir;
263 const float invarea = fabsf(klight->area.invarea);
264 bool sample_rectangle = (klight->area.invarea > 0.0f);
265
266 float3 light_P_new = *light_P;
267
268 if (in_volume_segment) {
269 light_P_new += sample_rectangle ?
270 rectangle_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, rand) :
271 ellipse_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, rand);
272 ls->pdf = invarea;
273 }
274 else {
275 if (klight->area.normalize_spread > 0) {
277 Ng,
278 &light_P_new,
279 &axis_u,
280 &len_u,
281 &axis_v,
282 &len_v,
283 klight->area.tan_half_spread,
284 &sample_rectangle))
285 {
286 return false;
287 }
288 }
289
290 if (sample_rectangle) {
291 ls->pdf = area_light_rect_sample(
292 ray_P, &light_P_new, axis_u, len_u, axis_v, len_v, rand, sample_coord);
293 }
294 else {
295 if (klight->area.tan_half_spread == 0.0f) {
296 ls->pdf = 1.0f;
297 }
298 else {
299 if (sample_coord) {
300 light_P_new += ellipse_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, rand);
301 }
302 ls->pdf = 4.0f * M_1_PI_F / (len_u * len_v);
303 }
304 }
305 }
306
307 if (sample_coord) {
308 *light_P = light_P_new;
309 ls->D = safe_normalize_len(*light_P - ray_P, &ls->t);
310 }
311
312 /* Convert radiant flux to radiance. */
313 ls->eval_fac = M_1_PI_F * invarea;
314
315 if (klight->area.normalize_spread > 0) {
316 /* Area Light spread angle attenuation */
317 ls->eval_fac *= area_light_spread_attenuation(
318 ls->D, Ng, klight->area.tan_half_spread, klight->area.normalize_spread);
319 }
320
321 if (in_volume_segment || (!sample_rectangle && klight->area.tan_half_spread > 0)) {
322 ls->pdf *= light_pdf_area_to_solid_angle(Ng, -ls->D, ls->t);
323 }
324
325 return in_volume_segment || ls->eval_fac > 0;
326}
327
328template<bool in_volume_segment>
330 const float2 rand,
331 const float3 P,
333{
334 ls->P = klight->co;
335 ls->Ng = klight->area.dir;
336
337 if (!in_volume_segment) {
338 if (dot(ls->P - P, ls->Ng) > 0.0f) {
339 return false;
340 }
341 }
342
343 if (!area_light_eval<in_volume_segment>(klight, P, &ls->P, ls, rand, true)) {
344 return false;
345 }
346
347 const float3 inplane = ls->P - klight->co;
348 float light_u = dot(inplane, klight->area.axis_u);
349 float light_v = dot(inplane, klight->area.axis_v);
350
351 if (!in_volume_segment && klight->area.normalize_spread > 0) {
352 const bool is_ellipse = area_light_is_ellipse(&klight->area);
353
354 /* Check whether the sampled point lies outside of the area light.
355 * For very small area lights, numerical issues can cause this to be
356 * slightly off since the sampling logic clamps the result right at the border,
357 * so allow for a small margin of error. */
358 const float len_u_epsilon = ((0.5f + 1e-7f) * klight->area.len_u + 1e-6f);
359 const float len_v_epsilon = ((0.5f + 1e-7f) * klight->area.len_v + 1e-6f);
360 if (is_ellipse && (sqr(light_u / len_u_epsilon) + sqr(light_v / len_v_epsilon) > 1.0f)) {
361 return false;
362 }
363 if (!is_ellipse && (fabsf(light_u) > len_u_epsilon || fabsf(light_v) > len_v_epsilon)) {
364 return false;
365 }
366 }
367
368 light_u /= klight->area.len_u;
369 light_v /= klight->area.len_v;
370
371 /* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
372 ls->u = light_v + 0.5f;
373 ls->v = -light_u - light_v;
374
375 return true;
376}
377
380 const float3 P)
381{
382 if (klight->area.tan_half_spread == 0) {
383 /* Update position on the light to keep the direction fixed. */
384 area_light_eval<false>(klight, P, &ls->P, ls, zero_float2(), true);
385 }
386 else {
387 ls->D = safe_normalize_len(ls->P - P, &ls->t);
388 area_light_eval<false>(klight, P, &ls->P, ls, zero_float2(), false);
389 /* Convert pdf to be in area measure. */
390 ls->pdf /= light_pdf_area_to_solid_angle(ls->Ng, -ls->D, ls->t);
391 }
392}
393
395 const ccl_private Ray *ccl_restrict ray,
396 ccl_private float *t,
397 ccl_private float *u,
398 ccl_private float *v)
399{
400 /* Area light. */
401 const float invarea = fabsf(klight->area.invarea);
402 const bool is_ellipse = area_light_is_ellipse(&klight->area);
403 if (invarea == 0.0f) {
404 return false;
405 }
406
407 const float3 inv_extent_u = klight->area.axis_u / klight->area.len_u;
408 const float3 inv_extent_v = klight->area.axis_v / klight->area.len_v;
409 const float3 Ng = klight->area.dir;
410
411 /* One sided. */
412 if (dot(ray->D, Ng) >= 0.0f) {
413 return false;
414 }
415
416 const float3 light_P = klight->co;
417
418 float3 P;
419 return ray_quad_intersect(ray->P,
420 ray->D,
421 ray->tmin,
422 ray->tmax,
423 light_P,
424 inv_extent_u,
425 inv_extent_v,
426 Ng,
427 &P,
428 t,
429 u,
430 v,
431 is_ellipse);
432}
433
435 const ccl_global KernelLight *klight,
437 const float3 ray_P,
438 const float3 ray_D,
440{
441 ls->u = isect->u;
442 ls->v = isect->v;
443 ls->D = ray_D;
444 ls->Ng = klight->area.dir;
445
446 float3 light_P = klight->co;
447 return area_light_eval<false>(klight, ray_P, &light_P, ls, zero_float2(), false);
448}
449
450/* Returns the maximal distance between the light center and the boundary. */
452{
453 return 0.5f * (area_light_is_ellipse(light) ? fmaxf(light->len_u, light->len_v) :
454 len(make_float2(light->len_u, light->len_v)));
455}
456
457/* Find the ray segment lit by the area light. */
459 float3 P,
460 float3 D,
462{
463 bool valid;
464 const float tan_half_spread = light->tan_half_spread;
465 float3 axis = light->dir;
466
467 const bool angle_almost_zero = (tan_half_spread < 1e-5f);
468 if (angle_almost_zero) {
469 /* Map to local coordinate of the light. Do not use `itfm` in `KernelLight` as there might be
470 * additional scaling in the light size. */
471 const Transform tfm = make_transform(light->axis_u, light->axis_v, axis);
472 P = transform_point(&tfm, P);
473 D = transform_direction(&tfm, D);
474 axis = make_float3(0.0f, 0.0f, 1.0f);
475
476 const float half_len_u = 0.5f * light->len_u;
477 const float half_len_v = 0.5f * light->len_v;
478 if (area_light_is_ellipse(light)) {
479 valid = ray_infinite_cylinder_intersect(P, D, half_len_u, half_len_v, t_range);
480 }
481 else {
482 const float3 bbox_min = make_float3(-half_len_u, -half_len_v, 0.0f);
483 const float3 bbox_max = make_float3(half_len_u, half_len_v, FLT_MAX);
484 valid = ray_aabb_intersect(bbox_min, bbox_max, P, D, t_range);
485 }
486 }
487 else {
488 /* Conservative estimation with the smallest possible cone covering the whole spread. */
489 const float3 apex_to_point = P + area_light_max_extent(light) / tan_half_spread * axis;
490 const float cos_angle_sq = 1.0f / (1.0f + sqr(tan_half_spread));
491
492 valid = ray_cone_intersect(axis, apex_to_point, D, cos_angle_sq, t_range);
493 }
494
495 /* Limit the range to the positive side of the area light. */
496 return valid && ray_plane_intersect(axis, P, D, t_range);
497}
498
499template<bool in_volume_segment>
501 const float3 centroid,
502 const float3 P,
503 const float3 N,
504 const float3 bcone_axis,
505 ccl_private float &cos_theta_u,
507 ccl_private float3 &point_to_centroid)
508{
509 /* TODO: a cheap substitute for minimal distance between point and primitive. Does it worth the
510 * overhead to compute the accurate minimal distance? */
511 float min_distance;
512 point_to_centroid = safe_normalize_len(centroid - P, &min_distance);
513 distance = make_float2(min_distance, min_distance);
514
515 cos_theta_u = FLT_MAX;
516
517 const float3 extentu = klight->area.axis_u * klight->area.len_u;
518 const float3 extentv = klight->area.axis_v * klight->area.len_v;
519 for (int i = 0; i < 4; i++) {
520 const float3 corner = ((i & 1) - 0.5f) * extentu + 0.5f * ((i & 2) - 1) * extentv + centroid;
521 float distance_point_to_corner;
522 const float3 point_to_corner = safe_normalize_len(corner - P, &distance_point_to_corner);
523 cos_theta_u = fminf(cos_theta_u, dot(point_to_centroid, point_to_corner));
524 if (!in_volume_segment) {
525 distance.x = fmaxf(distance.x, distance_point_to_corner);
526 }
527 }
528
529 const bool front_facing = dot(bcone_axis, point_to_centroid) < 0;
530 const bool shape_above_surface = dot(N, centroid - P) + fabsf(dot(N, extentu)) +
531 fabsf(dot(N, extentv)) >
532 0;
533
534 return front_facing && shape_above_surface;
535}
536
#define D
MINLINE float safe_divide(float a, float b)
MINLINE float safe_asinf(float a)
ccl_device bool area_light_spread_clamp_light(const float3 P, const float3 lightNg, ccl_private float3 *lightP, ccl_private float3 *axis_u, ccl_private float *len_u, ccl_private float3 *axis_v, ccl_private float *len_v, const float tan_half_spread, ccl_private bool *sample_rectangle)
Definition area.h:125
ccl_device_forceinline bool area_light_is_ellipse(const ccl_global KernelAreaLight *light)
Definition area.h:242
ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight, const float2 rand, const float3 P, ccl_private LightSample *ls)
Definition area.h:329
CCL_NAMESPACE_BEGIN ccl_device_inline float area_light_rect_sample(const float3 P, ccl_private float3 *light_p, const float3 axis_u, const float len_u, const float3 axis_v, const float len_v, const float2 rand, bool sample_coord)
Definition area.h:19
ccl_device_inline bool area_light_sample_from_intersection(const ccl_global KernelLight *klight, const ccl_private Intersection *ccl_restrict isect, const float3 ray_P, const float3 ray_D, ccl_private LightSample *ccl_restrict ls)
Definition area.h:434
ccl_device_inline bool area_light_intersect(const ccl_global KernelLight *klight, const ccl_private Ray *ccl_restrict ray, ccl_private float *t, ccl_private float *u, ccl_private float *v)
Definition area.h:394
ccl_device float area_light_spread_attenuation(const float3 D, const float3 lightNg, const float tan_half_spread, const float normalize_spread)
Definition area.h:106
ccl_device_inline bool area_light_valid_ray_segment(const ccl_global KernelAreaLight *light, float3 P, float3 D, ccl_private Interval< float > *t_range)
Definition area.h:458
ccl_device_inline bool area_light_eval(const ccl_global KernelLight *klight, const float3 ray_P, ccl_private float3 *light_P, ccl_private LightSample *ccl_restrict ls, const float2 rand, bool sample_coord)
Definition area.h:250
ccl_device_forceinline void area_light_mnee_sample_update(const ccl_global KernelLight *klight, ccl_private LightSample *ls, const float3 P)
Definition area.h:378
ccl_device_forceinline float area_light_max_extent(const ccl_global KernelAreaLight *light)
Definition area.h:451
ccl_device_forceinline bool area_light_tree_parameters(const ccl_global KernelLight *klight, const float3 centroid, const float3 P, const float3 N, const float3 bcone_axis, ccl_private float &cos_theta_u, ccl_private float2 &distance, ccl_private float3 &point_to_centroid)
Definition area.h:500
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
#define ccl_restrict
#define M_PI_2_F
#define ccl_device_forceinline
#define M_PI_4_F
#define ccl_private
#define ccl_device_inline
#define M_1_PI_F
#define ccl_global
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define copysignf(x, y)
VecBase< float, D > normalize(VecOp< float, D >) RET
#define sqrt
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
constexpr T clamp(T, U, U) RET
float distance(VecOp< float, D >, VecOp< float, D >) RET
ccl_device_inline float3 ellipse_sample(const float3 ru, const float3 rv, const float2 rand)
ccl_device float light_pdf_area_to_solid_angle(const float3 Ng, const float3 I, const float t)
ccl_device_inline float3 rectangle_sample(const float3 ru, const float3 rv, const float2 rand)
CCL_NAMESPACE_BEGIN ccl_device_inline float2 zero_float2()
Definition math_float2.h:13
ccl_device_inline float reduce_min(const float2 a)
ccl_device_inline float3 rotate_around_axis(const float3 p, const float3 axis, const float angle)
ccl_device_inline float3 safe_normalize_len(const float3 a, ccl_private float *t)
ccl_device_inline float tan_angle(const float3 a, const float3 b)
ccl_device_inline bool ray_cone_intersect(const float3 axis, const float3 P, float3 D, const float cos_angle_sq, ccl_private Interval< float > *t_range)
ccl_device bool ray_aabb_intersect(const float3 bbox_min, const float3 bbox_max, const float3 ray_P, const float3 ray_D, ccl_private Interval< float > *t_range)
ccl_device_inline bool ray_infinite_cylinder_intersect(const float3 P, const float3 D, const float len_u, const float len_v, ccl_private Interval< float > *t_range)
ccl_device bool ray_plane_intersect(const float3 N, const float3 P, const float3 ray_D, ccl_private Interval< float > *t_range)
ccl_device bool ray_quad_intersect(const float3 ray_P, const float3 ray_D, const float ray_tmin, const float ray_tmax, const float3 quad_P, const float3 inv_quad_u, const float3 inv_quad_v, const 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)
#define N
#define sqr
#define fabsf
#define sqrtf
#define ccl_device
#define fmaxf
#define sinf
#define make_float2
#define make_float4
#define fminf
#define M_PI_F
#define cosf
#define min(a, b)
Definition sort.cc:36
#define FLT_MAX
Definition stdcycles.h:14
float x
float y
float y
Definition sky_math.h:225
float z
Definition sky_math.h:225
float x
Definition sky_math.h:225
float w
Definition sky_math.h:225
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
ccl_device_inline Transform make_transform(const float a, const float b, const float c, const float d, const float e, const float f, const float g, const float h, const float i, const float j, const float k, const float l)
Definition transform.h:159
ccl_device_inline float3 transform_direction(const ccl_private Transform *t, const float3 a)
Definition transform.h:127
ccl_device_inline float3 transform_point(const ccl_private Transform *t, const float3 a)
Definition transform.h:56
uint len