Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/embree/kernels/geometry/curve_intersector_sweep.h
9905 views
1
// Copyright 2009-2021 Intel Corporation
2
// SPDX-License-Identifier: Apache-2.0
3
4
#pragma once
5
6
#include "../common/ray.h"
7
#include "cylinder.h"
8
#include "plane.h"
9
#include "line_intersector.h"
10
#include "curve_intersector_precalculations.h"
11
12
namespace embree
13
{
14
namespace isa
15
{
16
static const size_t numJacobianIterations = 5;
17
#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__)
18
static const size_t numBezierSubdivisions = 2;
19
#elif defined(__AVX__)
20
static const size_t numBezierSubdivisions = 2;
21
#else
22
static const size_t numBezierSubdivisions = 3;
23
#endif
24
25
struct BezierCurveHit
26
{
27
__forceinline BezierCurveHit() {}
28
29
__forceinline BezierCurveHit(const float t, const float u, const Vec3fa& Ng)
30
: t(t), u(u), v(0.0f), Ng(Ng) {}
31
32
__forceinline BezierCurveHit(const float t, const float u, const float v, const Vec3fa& Ng)
33
: t(t), u(u), v(v), Ng(Ng) {}
34
35
__forceinline void finalize() {}
36
37
public:
38
float t;
39
float u;
40
float v;
41
Vec3fa Ng;
42
};
43
44
template<typename NativeCurve3ff, typename Ray, typename Epilog>
45
__forceinline bool intersect_bezier_iterative_debug(const Ray& ray, const float dt, const NativeCurve3ff& curve, size_t i,
46
const vfloatx& u, const BBox<vfloatx>& tp, const BBox<vfloatx>& h0, const BBox<vfloatx>& h1,
47
const Vec3vfx& Ng, const Vec4vfx& dP0du, const Vec4vfx& dP3du,
48
const Epilog& epilog)
49
{
50
if (tp.lower[i]+dt > ray.tfar) return false;
51
Vec3fa Ng_o = Vec3fa(Ng.x[i],Ng.y[i],Ng.z[i]);
52
if (h0.lower[i] == tp.lower[i]) Ng_o = -Vec3fa(dP0du.x[i],dP0du.y[i],dP0du.z[i]);
53
if (h1.lower[i] == tp.lower[i]) Ng_o = +Vec3fa(dP3du.x[i],dP3du.y[i],dP3du.z[i]);
54
BezierCurveHit hit(tp.lower[i]+dt,u[i],Ng_o);
55
return epilog(hit);
56
}
57
58
template<typename NativeCurve3ff, typename Ray, typename Epilog>
59
__forceinline bool intersect_bezier_iterative_jacobian(const Ray& ray, const float dt, const NativeCurve3ff& curve, float u, float t, const Epilog& epilog)
60
{
61
const Vec3fa org = zero;
62
const Vec3fa dir = ray.dir;
63
const float length_ray_dir = length(dir);
64
65
/* error of curve evaluations is proportional to largest coordinate */
66
const BBox3ff box = curve.bounds();
67
const float P_err = 16.0f*float(ulp)*reduce_max(max(abs(box.lower),abs(box.upper)));
68
69
for (size_t i=0; i<numJacobianIterations; i++)
70
{
71
const Vec3fa Q = madd(Vec3fa(t),dir,org);
72
//const Vec3fa dQdu = zero;
73
const Vec3fa dQdt = dir;
74
const float Q_err = 16.0f*float(ulp)*length_ray_dir*t; // works as org=zero here
75
76
Vec3ff P,dPdu,ddPdu; curve.eval(u,P,dPdu,ddPdu);
77
//const Vec3fa dPdt = zero;
78
79
const Vec3fa R = Q-P;
80
const float len_R = length(R); //reduce_max(abs(R));
81
const float R_err = max(Q_err,P_err);
82
const Vec3fa dRdu = /*dQdu*/-dPdu;
83
const Vec3fa dRdt = dQdt;//-dPdt;
84
85
const Vec3fa T = normalize(dPdu);
86
const Vec3fa dTdu = dnormalize(dPdu,ddPdu);
87
//const Vec3fa dTdt = zero;
88
const float cos_err = P_err/length(dPdu);
89
90
/* Error estimate for dot(R,T):
91
92
dot(R,T) = cos(R,T) |R| |T|
93
= (cos(R,T) +- cos_error) * (|R| +- |R|_err) * (|T| +- |T|_err)
94
= cos(R,T)*|R|*|T|
95
+- cos(R,T)*(|R|*|T|_err + |T|*|R|_err)
96
+- cos_error*(|R| + |T|)
97
+- lower order terms
98
with cos(R,T) being in [0,1] and |T| = 1 we get:
99
dot(R,T)_err = |R|*|T|_err + |R|_err = cos_error*(|R|+1)
100
*/
101
102
const float f = dot(R,T);
103
const float f_err = len_R*P_err + R_err + cos_err*(1.0f+len_R);
104
const float dfdu = dot(dRdu,T) + dot(R,dTdu);
105
const float dfdt = dot(dRdt,T);// + dot(R,dTdt);
106
107
const float K = dot(R,R)-sqr(f);
108
const float dKdu = /*2.0f*/(dot(R,dRdu)-f*dfdu);
109
const float dKdt = /*2.0f*/(dot(R,dRdt)-f*dfdt);
110
const float rsqrt_K = rsqrt(K);
111
112
const float g = sqrt(K)-P.w;
113
const float g_err = R_err + f_err + 16.0f*float(ulp)*box.upper.w;
114
const float dgdu = /*0.5f*/dKdu*rsqrt_K-dPdu.w;
115
const float dgdt = /*0.5f*/dKdt*rsqrt_K;//-dPdt.w;
116
117
const LinearSpace2f J = LinearSpace2f(dfdu,dfdt,dgdu,dgdt);
118
const Vec2f dut = rcp(J)*Vec2f(f,g);
119
const Vec2f ut = Vec2f(u,t) - dut;
120
u = ut.x; t = ut.y;
121
122
if (abs(f) < f_err && abs(g) < g_err)
123
{
124
t+=dt;
125
if (!(ray.tnear() <= t && t <= ray.tfar)) return false; // rejects NaNs
126
if (!(u >= 0.0f && u <= 1.0f)) return false; // rejects NaNs
127
const Vec3fa R = normalize(Q-P);
128
const Vec3fa U = madd(Vec3fa(dPdu.w),R,dPdu);
129
const Vec3fa V = cross(dPdu,R);
130
BezierCurveHit hit(t,u,cross(V,U));
131
return epilog(hit);
132
}
133
}
134
return false;
135
}
136
137
#if !defined(__SYCL_DEVICE_ONLY__)
138
139
template<typename NativeCurve3ff, typename Ray, typename Epilog>
140
__forceinline bool intersect_bezier_recursive_jacobian(const Ray& ray, const float dt, const NativeCurve3ff& curve, const Epilog& epilog)
141
{
142
float u0 = 0.0f;
143
float u1 = 1.0f;
144
unsigned int depth = 1;
145
146
#if defined(__AVX__)
147
enum { VSIZEX_ = 8 };
148
typedef vbool8 vboolx; // maximally 8-wide to work around KNL issues
149
typedef vint8 vintx;
150
typedef vfloat8 vfloatx;
151
#else
152
enum { VSIZEX_ = 4 };
153
typedef vbool4 vboolx;
154
typedef vint4 vintx;
155
typedef vfloat4 vfloatx;
156
#endif
157
158
unsigned int maxDepth = numBezierSubdivisions;
159
bool found = false;
160
const Vec3fa org = zero;
161
const Vec3fa dir = ray.dir;
162
163
unsigned int sptr = 0;
164
const unsigned int stack_size = numBezierSubdivisions+1; // +1 because of unstable workaround below
165
struct StackEntry {
166
vboolx valid;
167
vfloatx tlower;
168
float u0;
169
float u1;
170
unsigned int depth;
171
};
172
StackEntry stack[stack_size];
173
goto entry;
174
175
/* terminate if stack is empty */
176
while (sptr)
177
{
178
/* pop from stack */
179
{
180
sptr--;
181
vboolx valid = stack[sptr].valid;
182
const vfloatx tlower = stack[sptr].tlower;
183
valid &= tlower+dt <= ray.tfar;
184
if (none(valid)) continue;
185
u0 = stack[sptr].u0;
186
u1 = stack[sptr].u1;
187
depth = stack[sptr].depth;
188
const size_t i = select_min(valid,tlower); clear(valid,i);
189
stack[sptr].valid = valid;
190
if (any(valid)) sptr++; // there are still items on the stack
191
192
/* process next segment */
193
const vfloatx vu0 = lerp(u0,u1,vfloatx(step)*(1.0f/(vfloatx::size-1)));
194
u0 = vu0[i+0];
195
u1 = vu0[i+1];
196
}
197
entry:
198
199
/* subdivide curve */
200
const float dscale = (u1-u0)*(1.0f/(3.0f*(vfloatx::size-1)));
201
const vfloatx vu0 = lerp(u0,u1,vfloatx(step)*(1.0f/(vfloatx::size-1)));
202
Vec4vfx P0, dP0du; curve.template veval<VSIZEX_>(vu0,P0,dP0du); dP0du = dP0du * Vec4vfx(dscale);
203
const Vec4vfx P3 = shift_right_1(P0);
204
const Vec4vfx dP3du = shift_right_1(dP0du);
205
const Vec4vfx P1 = P0 + dP0du;
206
const Vec4vfx P2 = P3 - dP3du;
207
208
/* calculate bounding cylinders */
209
const vfloatx rr1 = sqr_point_to_line_distance(Vec3vfx(dP0du),Vec3vfx(P3-P0));
210
const vfloatx rr2 = sqr_point_to_line_distance(Vec3vfx(dP3du),Vec3vfx(P3-P0));
211
const vfloatx maxr12 = sqrt(max(rr1,rr2));
212
const vfloatx one_plus_ulp = 1.0f+2.0f*float(ulp);
213
const vfloatx one_minus_ulp = 1.0f-2.0f*float(ulp);
214
vfloatx r_outer = max(P0.w,P1.w,P2.w,P3.w)+maxr12;
215
vfloatx r_inner = min(P0.w,P1.w,P2.w,P3.w)-maxr12;
216
r_outer = one_plus_ulp*r_outer;
217
r_inner = max(0.0f,one_minus_ulp*r_inner);
218
const CylinderN<vfloatx::size> cylinder_outer(Vec3vfx(P0),Vec3vfx(P3),r_outer);
219
const CylinderN<vfloatx::size> cylinder_inner(Vec3vfx(P0),Vec3vfx(P3),r_inner);
220
vboolx valid = true; clear(valid,vfloatx::size-1);
221
222
/* intersect with outer cylinder */
223
BBox<vfloatx> tc_outer; vfloatx u_outer0; Vec3vfx Ng_outer0; vfloatx u_outer1; Vec3vfx Ng_outer1;
224
valid &= cylinder_outer.intersect(org,dir,tc_outer,u_outer0,Ng_outer0,u_outer1,Ng_outer1);
225
if (none(valid)) continue;
226
227
/* intersect with cap-planes */
228
BBox<vfloatx> tp(ray.tnear()-dt,ray.tfar-dt);
229
tp = embree::intersect(tp,tc_outer);
230
BBox<vfloatx> h0 = HalfPlaneN<vfloatx::size>(Vec3vfx(P0),+Vec3vfx(dP0du)).intersect(org,dir);
231
tp = embree::intersect(tp,h0);
232
BBox<vfloatx> h1 = HalfPlaneN<vfloatx::size>(Vec3vfx(P3),-Vec3vfx(dP3du)).intersect(org,dir);
233
tp = embree::intersect(tp,h1);
234
valid &= tp.lower <= tp.upper;
235
if (none(valid)) continue;
236
237
/* clamp and correct u parameter */
238
u_outer0 = clamp(u_outer0,vfloatx(0.0f),vfloatx(1.0f));
239
u_outer1 = clamp(u_outer1,vfloatx(0.0f),vfloatx(1.0f));
240
u_outer0 = lerp(u0,u1,(vfloatx(step)+u_outer0)*(1.0f/float(vfloatx::size)));
241
u_outer1 = lerp(u0,u1,(vfloatx(step)+u_outer1)*(1.0f/float(vfloatx::size)));
242
243
/* intersect with inner cylinder */
244
BBox<vfloatx> tc_inner;
245
vfloatx u_inner0 = zero; Vec3vfx Ng_inner0 = zero; vfloatx u_inner1 = zero; Vec3vfx Ng_inner1 = zero;
246
const vboolx valid_inner = cylinder_inner.intersect(org,dir,tc_inner,u_inner0,Ng_inner0,u_inner1,Ng_inner1);
247
248
/* at the unstable area we subdivide deeper */
249
const vboolx unstable0 = (!valid_inner) | (abs(dot(Vec3vfx(Vec3fa(ray.dir)),Ng_inner0)) < 0.3f);
250
const vboolx unstable1 = (!valid_inner) | (abs(dot(Vec3vfx(Vec3fa(ray.dir)),Ng_inner1)) < 0.3f);
251
252
/* subtract the inner interval from the current hit interval */
253
BBox<vfloatx> tp0, tp1;
254
subtract(tp,tc_inner,tp0,tp1);
255
vboolx valid0 = valid & (tp0.lower <= tp0.upper);
256
vboolx valid1 = valid & (tp1.lower <= tp1.upper);
257
if (none(valid0 | valid1)) continue;
258
259
/* iterate over all first hits front to back */
260
const vintx termDepth0 = select(unstable0,vintx(maxDepth+1),vintx(maxDepth));
261
vboolx recursion_valid0 = valid0 & (depth < termDepth0);
262
valid0 &= depth >= termDepth0;
263
264
while (any(valid0))
265
{
266
const size_t i = select_min(valid0,tp0.lower); clear(valid0,i);
267
found = found | intersect_bezier_iterative_jacobian(ray,dt,curve,u_outer0[i],tp0.lower[i],epilog);
268
//found = found | intersect_bezier_iterative_debug (ray,dt,curve,i,u_outer0,tp0,h0,h1,Ng_outer0,dP0du,dP3du,epilog);
269
valid0 &= tp0.lower+dt <= ray.tfar;
270
}
271
valid1 &= tp1.lower+dt <= ray.tfar;
272
273
/* iterate over all second hits front to back */
274
const vintx termDepth1 = select(unstable1,vintx(maxDepth+1),vintx(maxDepth));
275
vboolx recursion_valid1 = valid1 & (depth < termDepth1);
276
valid1 &= depth >= termDepth1;
277
while (any(valid1))
278
{
279
const size_t i = select_min(valid1,tp1.lower); clear(valid1,i);
280
found = found | intersect_bezier_iterative_jacobian(ray,dt,curve,u_outer1[i],tp1.upper[i],epilog);
281
//found = found | intersect_bezier_iterative_debug (ray,dt,curve,i,u_outer1,tp1,h0,h1,Ng_outer1,dP0du,dP3du,epilog);
282
valid1 &= tp1.lower+dt <= ray.tfar;
283
}
284
285
/* push valid segments to stack */
286
recursion_valid0 &= tp0.lower+dt <= ray.tfar;
287
recursion_valid1 &= tp1.lower+dt <= ray.tfar;
288
const vboolx recursion_valid = recursion_valid0 | recursion_valid1;
289
if (any(recursion_valid))
290
{
291
assert(sptr < stack_size);
292
stack[sptr].valid = recursion_valid;
293
stack[sptr].tlower = select(recursion_valid0,tp0.lower,tp1.lower);
294
stack[sptr].u0 = u0;
295
stack[sptr].u1 = u1;
296
stack[sptr].depth = depth+1;
297
sptr++;
298
}
299
}
300
return found;
301
}
302
303
#else
304
305
template<typename NativeCurve3ff, typename Ray, typename Epilog>
306
__forceinline bool intersect_bezier_recursive_jacobian(const Ray& ray, const float dt, const NativeCurve3ff& curve, const Epilog& epilog)
307
{
308
const Vec3fa org = zero;
309
const Vec3fa dir = ray.dir;
310
const unsigned int max_depth = 7;
311
312
bool found = false;
313
314
struct ShortStack
315
{
316
/* pushes both children */
317
__forceinline void push() {
318
depth++;
319
}
320
321
/* pops next node */
322
__forceinline void pop() {
323
short_stack += (1<<(31-depth));
324
depth = 31-bsf(short_stack);
325
}
326
327
unsigned int depth = 0;
328
unsigned int short_stack = 0;
329
};
330
331
ShortStack stack;
332
333
do
334
{
335
const float u0 = (stack.short_stack+0*(1<<(31-stack.depth)))/float(0x80000000);
336
const float u1 = (stack.short_stack+1*(1<<(31-stack.depth)))/float(0x80000000);
337
338
/* subdivide bezier curve */
339
Vec3ff P0, dP0du; curve.eval(u0,P0,dP0du); dP0du = dP0du * (u1-u0);
340
Vec3ff P3, dP3du; curve.eval(u1,P3,dP3du); dP3du = dP3du * (u1-u0);
341
const Vec3ff P1 = P0 + dP0du*(1.0f/3.0f);
342
const Vec3ff P2 = P3 - dP3du*(1.0f/3.0f);
343
344
/* check if curve is well behaved, by checking deviation of tangents from straight line */
345
const Vec3ff W = Vec3ff(P3-P0,0.0f);
346
const Vec3ff dQ0 = abs(3.0f*(P1-P0) - W);
347
const Vec3ff dQ1 = abs(3.0f*(P2-P1) - W);
348
const Vec3ff dQ2 = abs(3.0f*(P3-P2) - W);
349
const Vec3ff max_dQ = max(dQ0,dQ1,dQ2);
350
const float m = max(max_dQ.x,max_dQ.y,max_dQ.z); //,max_dQ.w);
351
const float l = length(Vec3f(W));
352
const bool well_behaved = m < 0.2f*l;
353
354
if (!well_behaved && stack.depth < max_depth) {
355
stack.push();
356
continue;
357
}
358
359
/* calculate bounding cylinders */
360
const float rr1 = sqr_point_to_line_distance(Vec3f(dP0du),Vec3f(P3-P0));
361
const float rr2 = sqr_point_to_line_distance(Vec3f(dP3du),Vec3f(P3-P0));
362
const float maxr12 = sqrt(max(rr1,rr2));
363
const float one_plus_ulp = 1.0f+2.0f*float(ulp);
364
const float one_minus_ulp = 1.0f-2.0f*float(ulp);
365
float r_outer = max(P0.w,P1.w,P2.w,P3.w)+maxr12;
366
float r_inner = min(P0.w,P1.w,P2.w,P3.w)-maxr12;
367
r_outer = one_plus_ulp*r_outer;
368
r_inner = max(0.0f,one_minus_ulp*r_inner);
369
const Cylinder cylinder_outer(Vec3f(P0),Vec3f(P3),r_outer);
370
const Cylinder cylinder_inner(Vec3f(P0),Vec3f(P3),r_inner);
371
372
/* intersect with outer cylinder */
373
BBox<float> tc_outer; float u_outer0; Vec3fa Ng_outer0; float u_outer1; Vec3fa Ng_outer1;
374
if (!cylinder_outer.intersect(org,dir,tc_outer,u_outer0,Ng_outer0,u_outer1,Ng_outer1))
375
{
376
stack.pop();
377
continue;
378
}
379
380
/* intersect with cap-planes */
381
BBox<float> tp(ray.tnear()-dt,ray.tfar-dt);
382
tp = embree::intersect(tp,tc_outer);
383
BBox<float> h0 = HalfPlane(Vec3f(P0),+Vec3f(dP0du)).intersect(org,dir);
384
tp = embree::intersect(tp,h0);
385
BBox<float> h1 = HalfPlane(Vec3f(P3),-Vec3f(dP3du)).intersect(org,dir);
386
tp = embree::intersect(tp,h1);
387
if (tp.lower > tp.upper)
388
{
389
stack.pop();
390
continue;
391
}
392
393
bool valid = true;
394
395
/* clamp and correct u parameter */
396
u_outer0 = clamp(u_outer0,float(0.0f),float(1.0f));
397
u_outer1 = clamp(u_outer1,float(0.0f),float(1.0f));
398
u_outer0 = lerp(u0,u1,u_outer0);
399
u_outer1 = lerp(u0,u1,u_outer1);
400
401
/* intersect with inner cylinder */
402
BBox<float> tc_inner;
403
float u_inner0 = zero; Vec3fa Ng_inner0 = zero; float u_inner1 = zero; Vec3fa Ng_inner1 = zero;
404
const bool valid_inner = cylinder_inner.intersect(org,dir,tc_inner,u_inner0,Ng_inner0,u_inner1,Ng_inner1);
405
406
/* subtract the inner interval from the current hit interval */
407
BBox<float> tp0, tp1;
408
subtract(tp,tc_inner,tp0,tp1);
409
bool valid0 = valid & (tp0.lower <= tp0.upper);
410
bool valid1 = valid & (tp1.lower <= tp1.upper);
411
if (!(valid0 | valid1))
412
{
413
stack.pop();
414
continue;
415
}
416
417
/* at the unstable area we subdivide deeper */
418
const bool unstable0 = valid0 && ((!valid_inner) | (abs(dot(Vec3fa(ray.dir),Ng_inner0)) < 0.3f));
419
const bool unstable1 = valid1 && ((!valid_inner) | (abs(dot(Vec3fa(ray.dir),Ng_inner1)) < 0.3f));
420
421
if ((unstable0 | unstable1) && (stack.depth < max_depth)) {
422
stack.push();
423
continue;
424
}
425
426
if (valid0)
427
found |= intersect_bezier_iterative_jacobian(ray,dt,curve,u_outer0,tp0.lower,epilog);
428
429
/* the far hit cannot be closer, thus skip if we hit entry already */
430
valid1 &= tp1.lower+dt <= ray.tfar;
431
432
/* iterate over second hit */
433
if (valid1)
434
found |= intersect_bezier_iterative_jacobian(ray,dt,curve,u_outer1,tp1.upper,epilog);
435
436
stack.pop();
437
438
} while (stack.short_stack != 0x80000000);
439
440
return found;
441
}
442
443
#endif
444
445
template<template<typename Ty> class NativeCurve>
446
struct SweepCurve1Intersector1
447
{
448
typedef NativeCurve<Vec3ff> NativeCurve3ff;
449
450
template<typename Ray, typename Epilog>
451
__forceinline bool intersect(const CurvePrecalculations1& pre, Ray& ray,
452
RayQueryContext* context,
453
const CurveGeometry* geom, const unsigned int primID,
454
const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3,
455
const Epilog& epilog)
456
{
457
STAT3(normal.trav_prims,1,1,1);
458
459
/* move ray closer to make intersection stable */
460
NativeCurve3ff curve0(v0,v1,v2,v3);
461
curve0 = enlargeRadiusToMinWidth(context,geom,ray.org,curve0);
462
const float dt = dot(curve0.center()-ray.org,ray.dir)*rcp(dot(ray.dir,ray.dir));
463
const Vec3ff ref(madd(Vec3fa(dt),ray.dir,ray.org),0.0f);
464
const NativeCurve3ff curve1 = curve0-ref;
465
return intersect_bezier_recursive_jacobian(ray,dt,curve1,epilog);
466
}
467
};
468
469
template<template<typename Ty> class NativeCurve, int K>
470
struct SweepCurve1IntersectorK
471
{
472
typedef NativeCurve<Vec3ff> NativeCurve3ff;
473
474
struct Ray1
475
{
476
__forceinline Ray1(RayK<K>& ray, size_t k)
477
: org(ray.org.x[k],ray.org.y[k],ray.org.z[k]), dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]), _tnear(ray.tnear()[k]), tfar(ray.tfar[k]) {}
478
479
Vec3fa org;
480
Vec3fa dir;
481
float _tnear;
482
float& tfar;
483
484
__forceinline float& tnear() { return _tnear; }
485
//__forceinline float& tfar() { return _tfar; }
486
__forceinline const float& tnear() const { return _tnear; }
487
//__forceinline const float& tfar() const { return _tfar; }
488
489
};
490
491
template<typename Epilog>
492
__forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& vray, size_t k,
493
RayQueryContext* context,
494
const CurveGeometry* geom, const unsigned int primID,
495
const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3,
496
const Epilog& epilog)
497
{
498
STAT3(normal.trav_prims,1,1,1);
499
Ray1 ray(vray,k);
500
501
/* move ray closer to make intersection stable */
502
NativeCurve3ff curve0(v0,v1,v2,v3);
503
curve0 = enlargeRadiusToMinWidth(context,geom,ray.org,curve0);
504
const float dt = dot(curve0.center()-ray.org,ray.dir)*rcp(dot(ray.dir,ray.dir));
505
const Vec3ff ref(madd(Vec3fa(dt),ray.dir,ray.org),0.0f);
506
const NativeCurve3ff curve1 = curve0-ref;
507
return intersect_bezier_recursive_jacobian(ray,dt,curve1,epilog);
508
}
509
};
510
}
511
}
512
513