Blender V4.3
curve_intersect.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2020 Intel Corporation
2 *
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Adapted from Embree with modifications. */
6
7#pragma once
8
10
11/* Curve primitive intersection functions.
12 *
13 * The code here was adapted from curve_intersector_sweep.h in Embree, to get
14 * an exact match between Embree CPU ray-tracing and our GPU ray-tracing. */
15
16#define CURVE_NUM_BEZIER_SUBDIVISIONS 3
17#define CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE (CURVE_NUM_BEZIER_SUBDIVISIONS + 1)
18#define CURVE_NUM_BEZIER_STEPS 2
19#define CURVE_NUM_JACOBIAN_ITERATIONS 5
20
21#ifdef __HAIR__
22
23/* Catmull-rom curve evaluation. */
24
25ccl_device_inline float4 catmull_rom_basis_eval(const float4 curve[4], float u)
26{
27 const float t = u;
28 const float s = 1.0f - u;
29 const float n0 = -t * s * s;
30 const float n1 = 2.0f + t * t * (3.0f * t - 5.0f);
31 const float n2 = 2.0f + s * s * (3.0f * s - 5.0f);
32 const float n3 = -s * t * t;
33 return 0.5f * (curve[0] * n0 + curve[1] * n1 + curve[2] * n2 + curve[3] * n3);
34}
35
36ccl_device_inline float4 catmull_rom_basis_derivative(const float4 curve[4], float u)
37{
38 const float t = u;
39 const float s = 1.0f - u;
40 const float n0 = -s * s + 2.0f * s * t;
41 const float n1 = 2.0f * t * (3.0f * t - 5.0f) + 3.0f * t * t;
42 const float n2 = 2.0f * s * (3.0f * t + 2.0f) - 3.0f * s * s;
43 const float n3 = -2.0f * s * t + t * t;
44 return 0.5f * (curve[0] * n0 + curve[1] * n1 + curve[2] * n2 + curve[3] * n3);
45}
46
47ccl_device_inline float4 catmull_rom_basis_derivative2(const float4 curve[4], float u)
48{
49
50 const float t = u;
51 const float n0 = -3.0f * t + 2.0f;
52 const float n1 = 9.0f * t - 5.0f;
53 const float n2 = -9.0f * t + 4.0f;
54 const float n3 = 3.0f * t - 1.0f;
55 return (curve[0] * n0 + curve[1] * n1 + curve[2] * n2 + curve[3] * n3);
56}
57
58/* Thick Curve */
59
60ccl_device_inline float3 dnormalize(const float3 p, const float3 dp)
61{
62 const float pp = dot(p, p);
63 const float pdp = dot(p, dp);
64 return (pp * dp - pdp * p) / (pp * sqrtf(pp));
65}
66
67ccl_device_inline float sqr_point_to_line_distance(const float3 PmQ0, const float3 Q1mQ0)
68{
69 const float3 N = cross(PmQ0, Q1mQ0);
70 const float3 D = Q1mQ0;
71 return dot(N, N) / dot(D, D);
72}
73
74ccl_device_inline bool cylinder_intersect(const float3 cylinder_start,
75 const float3 cylinder_end,
76 const float cylinder_radius,
77 const float3 ray_D,
79 ccl_private float *u0_o,
80 ccl_private float3 *Ng0_o,
81 ccl_private float *u1_o,
82 ccl_private float3 *Ng1_o)
83{
84 /* Calculate quadratic equation to solve. */
85 const float rl = 1.0f / len(cylinder_end - cylinder_start);
86 const float3 P0 = cylinder_start, dP = (cylinder_end - cylinder_start) * rl;
87 const float3 O = -P0, dO = ray_D;
88
89 const float dOdO = dot(dO, dO);
90 const float OdO = dot(dO, O);
91 const float OO = dot(O, O);
92 const float dOz = dot(dP, dO);
93 const float Oz = dot(dP, O);
94
95 const float A = dOdO - sqr(dOz);
96 const float B = 2.0f * (OdO - dOz * Oz);
97 const float C = OO - sqr(Oz) - sqr(cylinder_radius);
98
99 /* We miss the cylinder if determinant is smaller than zero. */
100 const float D = B * B - 4.0f * A * C;
101 if (!(D >= 0.0f)) {
102 *t_o = make_float2(FLT_MAX, -FLT_MAX);
103 return false;
104 }
105
106 /* Special case for rays that are parallel to the cylinder. */
107 const float eps = 16.0f * FLT_EPSILON * max(fabsf(dOdO), fabsf(sqr(dOz)));
108 if (fabsf(A) < eps) {
109 if (C <= 0.0f) {
110 *t_o = make_float2(-FLT_MAX, FLT_MAX);
111 return true;
112 }
113 else {
114 *t_o = make_float2(-FLT_MAX, FLT_MAX);
115 return false;
116 }
117 }
118
119 /* Standard case for rays that are not parallel to the cylinder. */
120 const float Q = sqrtf(D);
121 const float rcp_2A = 1.0f / (2.0f * A);
122 const float t0 = (-B - Q) * rcp_2A;
123 const float t1 = (-B + Q) * rcp_2A;
124
125 /* Calculates u and Ng for near hit. */
126 {
127 *u0_o = (t0 * dOz + Oz) * rl;
128 const float3 Pr = t0 * ray_D;
129 const float3 Pl = (*u0_o) * (cylinder_end - cylinder_start) + cylinder_start;
130 *Ng0_o = Pr - Pl;
131 }
132
133 /* Calculates u and Ng for far hit. */
134 {
135 *u1_o = (t1 * dOz + Oz) * rl;
136 const float3 Pr = t1 * ray_D;
137 const float3 Pl = (*u1_o) * (cylinder_end - cylinder_start) + cylinder_start;
138 *Ng1_o = Pr - Pl;
139 }
140
141 *t_o = make_float2(t0, t1);
142
143 return true;
144}
145
146ccl_device_inline float2 half_plane_intersect(const float3 P, const float3 N, const float3 ray_D)
147{
148 const float3 O = -P;
149 const float3 D = ray_D;
150 const float ON = dot(O, N);
151 const float DN = dot(D, N);
152 const float min_rcp_input = 1e-18f;
153 const bool eps = fabsf(DN) < min_rcp_input;
154 const float t = -ON / DN;
155 const float lower = (eps || DN < 0.0f) ? -FLT_MAX : t;
156 const float upper = (eps || DN > 0.0f) ? FLT_MAX : t;
157 return make_float2(lower, upper);
158}
159
160ccl_device bool curve_intersect_iterative(const float3 ray_D,
161 const float ray_tmin,
162 ccl_private float *ray_tmax,
163 const float dt,
164 const float4 curve[4],
165 float u,
166 float t,
167 const bool use_backfacing,
169{
170 const float length_ray_D = len(ray_D);
171
172 /* Error of curve evaluations is proportional to largest coordinate. */
173 const float4 box_min = min(min(curve[0], curve[1]), min(curve[2], curve[3]));
174 const float4 box_max = max(min(curve[0], curve[1]), max(curve[2], curve[3]));
175 const float4 box_abs = max(fabs(box_min), fabs(box_max));
176 const float P_err = 16.0f * FLT_EPSILON *
177 max(box_abs.x, max(box_abs.y, max(box_abs.z, box_abs.w)));
178 const float radius_max = box_max.w;
179
180 for (int i = 0; i < CURVE_NUM_JACOBIAN_ITERATIONS; i++) {
181 const float3 Q = ray_D * t;
182 const float3 dQdt = ray_D;
183 const float Q_err = 16.0f * FLT_EPSILON * length_ray_D * t;
184
185 const float4 P4 = catmull_rom_basis_eval(curve, u);
186 const float4 dPdu4 = catmull_rom_basis_derivative(curve, u);
187
188 const float3 P = float4_to_float3(P4);
189 const float3 dPdu = float4_to_float3(dPdu4);
190 const float radius = P4.w;
191 const float dradiusdu = dPdu4.w;
192
193 const float3 ddPdu = float4_to_float3(catmull_rom_basis_derivative2(curve, u));
194
195 const float3 R = Q - P;
196 const float len_R = len(R);
197 const float R_err = max(Q_err, P_err);
198 const float3 dRdu = -dPdu;
199 const float3 dRdt = dQdt;
200
201 const float3 T = normalize(dPdu);
202 const float3 dTdu = dnormalize(dPdu, ddPdu);
203 const float cos_err = P_err / len(dPdu);
204
205 const float f = dot(R, T);
206 const float f_err = len_R * P_err + R_err + cos_err * (1.0f + len_R);
207 const float dfdu = dot(dRdu, T) + dot(R, dTdu);
208 const float dfdt = dot(dRdt, T);
209
210 const float K = dot(R, R) - sqr(f);
211 const float dKdu = (dot(R, dRdu) - f * dfdu);
212 const float dKdt = (dot(R, dRdt) - f * dfdt);
213 const float rsqrt_K = inversesqrtf(K);
214
215 const float g = sqrtf(K) - radius;
216 const float g_err = R_err + f_err + 16.0f * FLT_EPSILON * radius_max;
217 const float dgdu = dKdu * rsqrt_K - dradiusdu;
218 const float dgdt = dKdt * rsqrt_K;
219
220 const float invdet = 1.0f / (dfdu * dgdt - dgdu * dfdt);
221 u -= (dgdt * f - dfdt * g) * invdet;
222 t -= (-dgdu * f + dfdu * g) * invdet;
223
224 if (fabsf(f) < f_err && fabsf(g) < g_err) {
225 t += dt;
226 if (!(t >= ray_tmin && t <= *ray_tmax)) {
227 return false; /* Rejects NaNs */
228 }
229 if (!(u >= 0.0f && u <= 1.0f)) {
230 return false; /* Rejects NaNs */
231 }
232
233 /* Back-face culling. */
234 const float3 R = normalize(Q - P);
235 const float3 U = dradiusdu * R + dPdu;
236 const float3 V = cross(dPdu, R);
237 const float3 Ng = cross(V, U);
238 if (!use_backfacing && dot(ray_D, Ng) > 0.0f) {
239 return false;
240 }
241
242 /* Record intersection. */
243 *ray_tmax = t;
244 isect->t = t;
245 isect->u = u;
246 isect->v = 0.0f;
247
248 return true;
249 }
250 }
251 return false;
252}
253
254ccl_device bool curve_intersect_recursive(const float3 ray_P,
255 const float3 ray_D,
256 const float ray_tmin,
257 float ray_tmax,
258 float4 curve[4],
260{
261 /* Move ray closer to make intersection stable. */
262 const float3 center = float4_to_float3(0.25f * (curve[0] + curve[1] + curve[2] + curve[3]));
263 const float dt = dot(center - ray_P, ray_D) / dot(ray_D, ray_D);
264 const float3 ref = ray_P + ray_D * dt;
265 const float4 ref4 = make_float4(ref.x, ref.y, ref.z, 0.0f);
266 curve[0] -= ref4;
267 curve[1] -= ref4;
268 curve[2] -= ref4;
269 curve[3] -= ref4;
270
271 const bool use_backfacing = false;
272 const float step_size = 1.0f / (float)(CURVE_NUM_BEZIER_STEPS);
273
274 int depth = 0;
275
276 /* todo: optimize stack for GPU somehow? Possibly some bitflags are enough, and
277 * u0/u1 can be derived from the depth. */
278 struct {
279 float u0, u1;
280 int i;
282
283 bool found = false;
284
285 float u0 = 0.0f;
286 float u1 = 1.0f;
287 int i = 0;
288
289 while (1) {
290 for (; i < CURVE_NUM_BEZIER_STEPS; i++) {
291 const float step = i * step_size;
292
293 /* Subdivide curve. */
294 const float dscale = (u1 - u0) * (1.0f / 3.0f) * step_size;
295 const float vu0 = mix(u0, u1, step);
296 const float vu1 = mix(u0, u1, step + step_size);
297
298 const float4 P0 = catmull_rom_basis_eval(curve, vu0);
299 const float4 dP0du = dscale * catmull_rom_basis_derivative(curve, vu0);
300 const float4 P3 = catmull_rom_basis_eval(curve, vu1);
301 const float4 dP3du = dscale * catmull_rom_basis_derivative(curve, vu1);
302
303 const float4 P1 = P0 + dP0du;
304 const float4 P2 = P3 - dP3du;
305
306 /* Calculate bounding cylinders. */
307 const float rr1 = sqr_point_to_line_distance(float4_to_float3(dP0du),
308 float4_to_float3(P3 - P0));
309 const float rr2 = sqr_point_to_line_distance(float4_to_float3(dP3du),
310 float4_to_float3(P3 - P0));
311 const float maxr12 = sqrtf(max(rr1, rr2));
312 const float one_plus_ulp = 1.0f + 2.0f * FLT_EPSILON;
313 const float one_minus_ulp = 1.0f - 2.0f * FLT_EPSILON;
314 float r_outer = max(max(P0.w, P1.w), max(P2.w, P3.w)) + maxr12;
315 float r_inner = min(min(P0.w, P1.w), min(P2.w, P3.w)) - maxr12;
316 r_outer = one_plus_ulp * r_outer;
317 r_inner = max(0.0f, one_minus_ulp * r_inner);
318 bool valid = true;
319
320 /* Intersect with outer cylinder. */
321 float2 tc_outer;
322 float u_outer0, u_outer1;
323 float3 Ng_outer0, Ng_outer1;
324 valid = cylinder_intersect(float4_to_float3(P0),
326 r_outer,
327 ray_D,
328 &tc_outer,
329 &u_outer0,
330 &Ng_outer0,
331 &u_outer1,
332 &Ng_outer1);
333 if (!valid) {
334 continue;
335 }
336
337 /* Intersect with cap-planes. */
338 float2 tp = make_float2(ray_tmin - dt, ray_tmax - dt);
339 tp = make_float2(max(tp.x, tc_outer.x), min(tp.y, tc_outer.y));
340 const float2 h0 = half_plane_intersect(float4_to_float3(P0), float4_to_float3(dP0du), ray_D);
341 tp = make_float2(max(tp.x, h0.x), min(tp.y, h0.y));
342 const float2 h1 = half_plane_intersect(
343 float4_to_float3(P3), -float4_to_float3(dP3du), ray_D);
344 tp = make_float2(max(tp.x, h1.x), min(tp.y, h1.y));
345 valid = tp.x <= tp.y;
346 if (!valid) {
347 continue;
348 }
349
350 /* Clamp and correct u parameter. */
351 u_outer0 = clamp(u_outer0, 0.0f, 1.0f);
352 u_outer1 = clamp(u_outer1, 0.0f, 1.0f);
353 u_outer0 = mix(u0, u1, (step + u_outer0) * (1.0f / (float)(CURVE_NUM_BEZIER_STEPS + 1)));
354 u_outer1 = mix(u0, u1, (step + u_outer1) * (1.0f / (float)(CURVE_NUM_BEZIER_STEPS + 1)));
355
356 /* Intersect with inner cylinder. */
357 float2 tc_inner;
358 float u_inner0, u_inner1;
359 float3 Ng_inner0, Ng_inner1;
360 const bool valid_inner = cylinder_intersect(float4_to_float3(P0),
362 r_inner,
363 ray_D,
364 &tc_inner,
365 &u_inner0,
366 &Ng_inner0,
367 &u_inner1,
368 &Ng_inner1);
369
370 /* At the unstable area we subdivide deeper. */
371# if 0
372 const bool unstable0 = (!valid_inner) |
373 (fabsf(dot(normalize(ray_D), normalize(Ng_inner0))) < 0.3f);
374 const bool unstable1 = (!valid_inner) |
375 (fabsf(dot(normalize(ray_D), normalize(Ng_inner1))) < 0.3f);
376# else
377 /* On the GPU appears to be a little faster if always enabled. */
378 (void)valid_inner;
379
380 const bool unstable0 = true;
381 const bool unstable1 = true;
382# endif
383
384 /* Subtract the inner interval from the current hit interval. */
385 const float eps = 0.001f;
386 float2 tp0 = make_float2(tp.x, min(tp.y, tc_inner.x));
387 float2 tp1 = make_float2(max(tp.x, tc_inner.y), tp.y);
388 /* The X component should be less than the Y component for a valid intersection,
389 * but due to precision issues, the X component can sometimes be greater than
390 * Y by a small amount, leading to missing intersections. */
391 bool valid0 = valid && ((tp0.x - tp0.y) < eps);
392 bool valid1 = valid && ((tp1.x - tp1.y) < eps);
393 if (!(valid0 || valid1)) {
394 continue;
395 }
396
397 /* Process one or two hits. */
398 bool recurse = false;
399 if (valid0) {
400 const int termDepth = unstable0 ? CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE :
402 if (depth >= termDepth) {
403 found |= curve_intersect_iterative(
404 ray_D, ray_tmin, &ray_tmax, dt, curve, u_outer0, tp0.x, use_backfacing, isect);
405 }
406 else {
407 recurse = true;
408 }
409 }
410
411 const float t1 = tp1.x + dt;
412 if (valid1 && (t1 >= ray_tmin && t1 <= ray_tmax)) {
413 const int termDepth = unstable1 ? CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE :
415 if (depth >= termDepth) {
416 found |= curve_intersect_iterative(
417 ray_D, ray_tmin, &ray_tmax, dt, curve, u_outer1, tp1.y, use_backfacing, isect);
418 }
419 else {
420 recurse = true;
421 }
422 }
423
424 if (recurse) {
425 stack[depth].u0 = u0;
426 stack[depth].u1 = u1;
427 stack[depth].i = i + 1;
428 depth++;
429
430 u0 = vu0;
431 u1 = vu1;
432 i = -1;
433 }
434 }
435
436 if (depth > 0) {
437 depth--;
438 u0 = stack[depth].u0;
439 u1 = stack[depth].u1;
440 i = stack[depth].i;
441 }
442 else {
443 break;
444 }
445 }
446
447 return found;
448}
449
450/* Ribbons */
451
452ccl_device_inline bool cylinder_culling_test(const float2 p1, const float2 p2, const float r)
453{
454 /* Performs culling against a cylinder. */
455 const float2 dp = p2 - p1;
456 const float num = dp.x * p1.y - dp.y * p1.x;
457 const float den2 = dot(dp, dp);
458 return num * num <= r * r * den2;
459}
460
467ccl_device_inline bool ribbon_intersect_quad(const float ray_tmin,
468 const float ray_tmax,
469 const float3 quad_v0,
470 const float3 quad_v1,
471 const float3 quad_v2,
472 const float3 quad_v3,
473 ccl_private float *u_o,
474 ccl_private float *v_o,
475 ccl_private float *t_o)
476{
477 /* Calculate vertices relative to ray origin? */
478 const float3 O = make_float3(0.0f, 0.0f, 0.0f);
479 const float3 D = make_float3(0.0f, 0.0f, 1.0f);
480 const float3 va = quad_v0 - O;
481 const float3 vb = quad_v1 - O;
482 const float3 vc = quad_v2 - O;
483 const float3 vd = quad_v3 - O;
484
485 const float3 edb = vb - vd;
486 const float WW = dot(cross(vd, edb), D);
487 const float3 v0 = (WW <= 0.0f) ? va : vc;
488 const float3 v1 = (WW <= 0.0f) ? vb : vd;
489 const float3 v2 = (WW <= 0.0f) ? vd : vb;
490
491 /* Calculate edges? */
492 const float3 e0 = v2 - v0;
493 const float3 e1 = v0 - v1;
494
495 /* perform edge tests */
496 const float U = dot(cross(v0, e0), D);
497 const float V = dot(cross(v1, e1), D);
498 if (!(max(U, V) <= 0.0f)) {
499 return false;
500 }
501
502 /* Calculate geometry normal and denominator? */
503 const float3 Ng = cross(e1, e0);
504 const float den = dot(Ng, D);
505 const float rcpDen = 1.0f / den;
506
507 /* Perform depth test? */
508 const float t = rcpDen * dot(v0, Ng);
509 if (!(t >= ray_tmin && t <= ray_tmax)) {
510 return false;
511 }
512
513 /* Avoid division by 0? */
514 if (!(den != 0.0f)) {
515 return false;
516 }
517
518 /* Update hit information? */
519 *t_o = t;
520 *u_o = U * rcpDen;
521 *v_o = V * rcpDen;
522 *u_o = (WW <= 0.0f) ? *u_o : 1.0f - *u_o;
523 *v_o = (WW <= 0.0f) ? *v_o : 1.0f - *v_o;
524 return true;
525}
526
527ccl_device_inline void ribbon_ray_space(const float3 ray_D,
528 const float ray_D_invlen,
529 float3 ray_space[3])
530{
531 const float3 D = ray_D * ray_D_invlen;
532 const float3 dx0 = make_float3(0, D.z, -D.y);
533 const float3 dx1 = make_float3(-D.z, 0, D.x);
534 ray_space[0] = normalize(dot(dx0, dx0) > dot(dx1, dx1) ? dx0 : dx1);
535 ray_space[1] = normalize(cross(D, ray_space[0]));
536 ray_space[2] = D * ray_D_invlen;
537}
538
539ccl_device_inline float4 ribbon_to_ray_space(const float3 ray_space[3],
540 const float3 ray_org,
541 const float4 P4)
542{
543 float3 P = float4_to_float3(P4) - ray_org;
544 return make_float4(dot(ray_space[0], P), dot(ray_space[1], P), dot(ray_space[2], P), P4.w);
545}
546
547ccl_device_inline bool ribbon_intersect(const float3 ray_org,
548 const float3 ray_D,
549 const float ray_tmin,
550 float ray_tmax,
551 const int N,
552 float4 curve[4],
554{
555 /* Transform control points into ray space. */
556 const float ray_D_invlen = 1.0f / len(ray_D);
557 float3 ray_space[3];
558 ribbon_ray_space(ray_D, ray_D_invlen, ray_space);
559
560 curve[0] = ribbon_to_ray_space(ray_space, ray_org, curve[0]);
561 curve[1] = ribbon_to_ray_space(ray_space, ray_org, curve[1]);
562 curve[2] = ribbon_to_ray_space(ray_space, ray_org, curve[2]);
563 curve[3] = ribbon_to_ray_space(ray_space, ray_org, curve[3]);
564
565 const float4 mx = max(max(fabs(curve[0]), fabs(curve[1])), max(fabs(curve[2]), fabs(curve[3])));
566 const float eps = 4.0f * FLT_EPSILON * max(max(mx.x, mx.y), max(mx.z, mx.w));
567 const float step_size = 1.0f / (float)N;
568
569 /* Evaluate first point and radius scaled normal direction. */
570 float4 p0 = catmull_rom_basis_eval(curve, 0.0f);
571 float3 dp0dt = float4_to_float3(catmull_rom_basis_derivative(curve, 0.0f));
572 if (reduce_max(fabs(dp0dt)) < eps) {
573 const float4 p1 = catmull_rom_basis_eval(curve, step_size);
574 dp0dt = float4_to_float3(p1 - p0);
575 }
576 float3 wn0 = normalize(make_float3(dp0dt.y, -dp0dt.x, 0.0f)) * p0.w;
577
578 /* Evaluate the bezier curve. */
579 for (int i = 0; i < N; i++) {
580 const float u = i * step_size;
581 const float4 p1 = catmull_rom_basis_eval(curve, u + step_size);
582 const bool valid = cylinder_culling_test(
583 make_float2(p0.x, p0.y), make_float2(p1.x, p1.y), max(p0.w, p1.w));
584
585 /* Evaluate next point. */
586 float3 dp1dt = float4_to_float3(catmull_rom_basis_derivative(curve, u + step_size));
587 dp1dt = (reduce_max(fabs(dp1dt)) < eps) ? float4_to_float3(p1 - p0) : dp1dt;
588 const float3 wn1 = normalize(make_float3(dp1dt.y, -dp1dt.x, 0.0f)) * p1.w;
589
590 if (valid) {
591 /* Construct quad coordinates. */
592 const float3 lp0 = float4_to_float3(p0) + wn0;
593 const float3 lp1 = float4_to_float3(p1) + wn1;
594 const float3 up0 = float4_to_float3(p0) - wn0;
595 const float3 up1 = float4_to_float3(p1) - wn1;
596
597 /* Intersect quad. */
598 float vu, vv, vt;
599 bool valid0 = ribbon_intersect_quad(ray_tmin, ray_tmax, lp0, lp1, up1, up0, &vu, &vv, &vt);
600
601 if (valid0) {
602 /* ignore self intersections */
603 const float avoidance_factor = 2.0f;
604 if (avoidance_factor != 0.0f) {
605 float r = mix(p0.w, p1.w, vu);
606 valid0 = vt > avoidance_factor * r * ray_D_invlen;
607 }
608
609 if (valid0) {
610 vv = 2.0f * vv - 1.0f;
611
612 /* Record intersection. */
613 ray_tmax = vt;
614 isect->t = vt;
615 isect->u = u + vu * step_size;
616 isect->v = vv;
617 return true;
618 }
619 }
620 }
621
622 /* Store point for next step. */
623 p0 = p1;
624 wn0 = wn1;
625 }
626 return false;
627}
628
629ccl_device_forceinline bool curve_intersect(KernelGlobals kg,
631 const float3 ray_P,
632 const float3 ray_D,
633 const float tmin,
634 const float tmax,
635 int object,
636 int prim,
637 float time,
638 int type)
639{
640 const bool is_motion = (type & PRIMITIVE_MOTION);
641
642 KernelCurve kcurve = kernel_data_fetch(curves, prim);
643
644 int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(type);
645 int k1 = k0 + 1;
646 int ka = max(k0 - 1, kcurve.first_key);
647 int kb = min(k1 + 1, kcurve.first_key + kcurve.num_keys - 1);
648
649 float4 curve[4];
650 if (!is_motion) {
651 curve[0] = kernel_data_fetch(curve_keys, ka);
652 curve[1] = kernel_data_fetch(curve_keys, k0);
653 curve[2] = kernel_data_fetch(curve_keys, k1);
654 curve[3] = kernel_data_fetch(curve_keys, kb);
655 }
656 else {
657 motion_curve_keys(kg, object, time, ka, k0, k1, kb, curve);
658 }
659
660 if (type & PRIMITIVE_CURVE_RIBBON) {
661 /* todo: adaptive number of subdivisions could help performance here. */
662 const int subdivisions = kernel_data.bvh.curve_subdivisions;
663 if (ribbon_intersect(ray_P, ray_D, tmin, tmax, subdivisions, curve, isect)) {
664 isect->prim = prim;
665 isect->object = object;
666 isect->type = type;
667 return true;
668 }
669
670 return false;
671 }
672 else {
673 if (curve_intersect_recursive(ray_P, ray_D, tmin, tmax, curve, isect)) {
674 isect->prim = prim;
675 isect->object = object;
676 isect->type = type;
677 return true;
678 }
679
680 return false;
681 }
682}
683
684ccl_device_inline void curve_shader_setup(KernelGlobals kg,
686 float3 P,
687 float3 D,
688 float t,
689 const int isect_prim)
690{
691 if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
692 const Transform tfm = object_get_inverse_transform(kg, sd);
693
694 P = transform_point(&tfm, P);
695 D = transform_direction(&tfm, D * t);
696 D = safe_normalize_len(D, &t);
697 }
698
699 KernelCurve kcurve = kernel_data_fetch(curves, isect_prim);
700
701 int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
702 int k1 = k0 + 1;
703 int ka = max(k0 - 1, kcurve.first_key);
704 int kb = min(k1 + 1, kcurve.first_key + kcurve.num_keys - 1);
705
706 float4 P_curve[4];
707
708 if (!(sd->type & PRIMITIVE_MOTION)) {
709 P_curve[0] = kernel_data_fetch(curve_keys, ka);
710 P_curve[1] = kernel_data_fetch(curve_keys, k0);
711 P_curve[2] = kernel_data_fetch(curve_keys, k1);
712 P_curve[3] = kernel_data_fetch(curve_keys, kb);
713 }
714 else {
715 motion_curve_keys(kg, sd->object, sd->time, ka, k0, k1, kb, P_curve);
716 }
717
718 P = P + D * t;
719
720 const float4 dPdu4 = catmull_rom_basis_derivative(P_curve, sd->u);
721 const float3 dPdu = float4_to_float3(dPdu4);
722
723 if (sd->type & PRIMITIVE_CURVE_RIBBON) {
724 /* Rounded smooth normals for ribbons, to approximate thick curve shape. */
725 const float3 tangent = normalize(dPdu);
726 const float3 bitangent = normalize(cross(tangent, -D));
727 const float sine = sd->v;
728 const float cosine = cos_from_sin(sine);
729
730 sd->N = normalize(sine * bitangent - cosine * normalize(cross(tangent, bitangent)));
731# if 0
732 /* This approximates the position and geometric normal of a thick curve too,
733 * but gives too many issues with wrong self intersections. */
734 const float dPdu_radius = dPdu4.w;
735 sd->Ng = sd->N;
736 P += sd->N * dPdu_radius;
737# endif
738 }
739 else {
740 /* Thick curves, compute normal using direction from inside the curve.
741 * This could be optimized by recording the normal in the intersection,
742 * however for Optix this would go beyond the size of the payload. */
743 /* NOTE: It is possible that P will be the same as P_inside (precision issues, or very small
744 * radius). In this case use the view direction to approximate the normal. */
745 const float3 P_inside = float4_to_float3(catmull_rom_basis_eval(P_curve, sd->u));
746 const float3 N = (!isequal(P, P_inside)) ? normalize(P - P_inside) : -sd->wi;
747
748 sd->N = N;
749 sd->v = 0.0f;
750 }
751
752# ifdef __DPDU__
753 /* dPdu/dPdv */
754 sd->dPdu = dPdu;
755# endif
756
757 /* Convert to world space. */
758 if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
760 object_normal_transform_auto(kg, sd, &sd->N);
761 object_dir_transform_auto(kg, sd, &sd->dPdu);
762 }
763
764 sd->P = P;
765 sd->Ng = (sd->type & PRIMITIVE_CURVE_RIBBON) ? sd->wi : sd->N;
766 sd->dPdv = cross(sd->dPdu, sd->Ng);
767 sd->shader = kernel_data_fetch(curves, sd->prim).shader_id;
768}
769
770#endif
771
#define K(key)
#define C
Definition RandGen.cpp:29
ATTR_WARN_UNUSED_RESULT const BMVert * v2
#define A
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
#define CURVE_NUM_BEZIER_SUBDIVISIONS_UNSTABLE
#define CURVE_NUM_BEZIER_STEPS
#define CURVE_NUM_JACOBIAN_ITERATIONS
#define CURVE_NUM_BEZIER_SUBDIVISIONS
#define kernel_data
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
#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)
ccl_device_forceinline float2 make_float2(const float x, const float y)
#define fabsf(x)
#define sqrtf(x)
int len
draw_view in_light_buf[] float
#define mix(a, b, c)
Definition hash.h:36
#define object_normal_transform_auto
#define object_position_transform_auto
#define object_dir_transform_auto
ccl_device_inline Transform object_get_inverse_transform(KernelGlobals kg, ccl_private const ShaderData *sd)
@ PRIMITIVE_MOTION
@ PRIMITIVE_CURVE_RIBBON
#define PRIMITIVE_UNPACK_SEGMENT(type)
ShaderData
@ SD_OBJECT_TRANSFORM_APPLIED
ccl_device_inline float reduce_max(const float2 a)
ccl_device_inline float cross(const float2 a, const float2 b)
ccl_device_inline float2 fabs(const float2 a)
ccl_device_inline bool isequal(const float2 a, const float2 b)
ccl_device_inline float3 safe_normalize_len(const float3 a, ccl_private float *t)
#define N
#define B
#define R
T step(const T &edge, const T &value)
VecBase< float, 4 > float4
const btScalar eps
Definition poly34.cpp:11
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
float x
float y
float z
Definition sky_float3.h:27
float y
Definition sky_float3.h:27
float x
Definition sky_float3.h:27
ccl_device_inline float3 transform_direction(ccl_private const Transform *t, const float3 a)
Definition transform.h:94
CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a)
Definition transform.h:63
float max
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 float3 float4_to_float3(const float4 a)
Definition util/math.h:535
ccl_device_inline float cos_from_sin(const float s)
Definition util/math.h:792
ccl_device_inline int clamp(int a, int mn, int mx)
Definition util/math.h:379
CCL_NAMESPACE_BEGIN struct Window V