Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/embree/kernels/geometry/roundline_intersector.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 "curve_intersector_precalculations.h"
8
9
10
/*
11
12
This file implements the intersection of a ray with a round linear
13
curve segment. We define the geometry of such a round linear curve
14
segment from point p0 with radius r0 to point p1 with radius r1
15
using the cone that touches spheres p0/r0 and p1/r1 tangentially
16
plus the sphere p1/r1. We denote the tangentially touching cone from
17
p0/r0 to p1/r1 with cone(p0,r0,p1,r1) and the cone plus the ending
18
sphere with cone_sphere(p0,r0,p1,r1).
19
20
For multiple connected round linear curve segments this construction
21
yield a proper shape when viewed from the outside. Using the
22
following CSG we can also handle the interior in most common cases:
23
24
round_linear_curve(pl,rl,p0,r0,p1,r1,pr,rr) =
25
cone_sphere(p0,r0,p1,r1) - cone(pl,rl,p0,r0) - cone(p1,r1,pr,rr)
26
27
Thus by subtracting the neighboring cone geometries, we cut away
28
parts of the center cone_sphere surface which lie inside the
29
combined curve. This approach works as long as geometry of the
30
current cone_sphere penetrates into direct neighbor segments only,
31
and not into segments further away.
32
33
To construct a cone that touches two spheres at p0 and p1 with r0
34
and r1, one has to increase the cone radius at r0 and r1 to obtain
35
larger radii w0 and w1, such that the infinite cone properly touches
36
the spheres. From the paper "Ray Tracing Generalized Tube
37
Primitives: Method and Applications"
38
(https://www.researchgate.net/publication/334378683_Ray_Tracing_Generalized_Tube_Primitives_Method_and_Applications)
39
one can derive the following equations for these increased
40
radii:
41
42
sr = 1.0f / sqrt(1-sqr(dr)/sqr(p1-p0))
43
w0 = sr*r0
44
w1 = sr*r1
45
46
Further, we want the cone to start where it touches the sphere at p0
47
and to end where it touches sphere at p1. Therefore, we need to
48
construct clipping locations y0 and y1 for the start and end of the
49
cone. These start and end clipping location of the cone can get
50
calculated as:
51
52
Y0 = - r0 * (r1-r0) / length(p1-p0)
53
Y1 = length(p1-p0) - r1 * (r1-r0) / length(p1-p0)
54
55
Where the cone starts a distance Y0 and ends a distance Y1 away of
56
point p0 along the cone center. The distance between Y1-Y0 can get
57
calculated as:
58
59
dY = length(p1-p0) - (r1-r0)^2 / length(p1-p0)
60
61
In the code below, Y will always be scaled by length(p1-p0) to
62
obtain y and you will find the terms r0*(r1-r0) and
63
(p1-p0)^2-(r1-r0)^2.
64
65
*/
66
67
namespace embree
68
{
69
namespace isa
70
{
71
template<int M>
72
struct RoundLineIntersectorHitM
73
{
74
__forceinline RoundLineIntersectorHitM() {}
75
76
__forceinline RoundLineIntersectorHitM(const vfloat<M>& u, const vfloat<M>& v, const vfloat<M>& t, const Vec3vf<M>& Ng)
77
: vu(u), vv(v), vt(t), vNg(Ng) {}
78
79
__forceinline void finalize() {}
80
81
__forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
82
__forceinline float t (const size_t i) const { return vt[i]; }
83
__forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }
84
85
__forceinline Vec2vf<M> uv() const { return Vec2vf<M>(vu,vv); }
86
__forceinline vfloat<M> t () const { return vt; }
87
__forceinline Vec3vf<M> Ng() const { return vNg; }
88
89
public:
90
vfloat<M> vu;
91
vfloat<M> vv;
92
vfloat<M> vt;
93
Vec3vf<M> vNg;
94
};
95
96
namespace __roundline_internal
97
{
98
template<int M>
99
struct ConeGeometry
100
{
101
ConeGeometry (const Vec4vf<M>& a, const Vec4vf<M>& b)
102
: p0(a.xyz()), p1(b.xyz()), dP(p1-p0), dPdP(dot(dP,dP)), r0(a.w), sqr_r0(sqr(r0)), r1(b.w), dr(r1-r0), drdr(dr*dr), r0dr (r0*dr), g(dPdP - drdr) {}
103
104
/*
105
106
This function tests if a point is accepted by first cone
107
clipping plane.
108
109
First, we need to project the point onto the line p0->p1:
110
111
Y = (p-p0)*(p1-p0)/length(p1-p0)
112
113
This value y is the distance to the projection point from
114
p0. The clip distances are calculated as:
115
116
Y0 = - r0 * (r1-r0) / length(p1-p0)
117
Y1 = length(p1-p0) - r1 * (r1-r0) / length(p1-p0)
118
119
Thus to test if the point p is accepted by the first
120
clipping plane we need to test Y > Y0 and to test if it
121
is accepted by the second clipping plane we need to test
122
Y < Y1.
123
124
By multiplying the calculations with length(p1-p0) these
125
calculation can get simplied to:
126
127
y = (p-p0)*(p1-p0)
128
y0 = - r0 * (r1-r0)
129
y1 = (p1-p0)^2 - r1 * (r1-r0)
130
131
and the test y > y0 and y < y1.
132
133
*/
134
135
__forceinline vbool<M> isClippedByPlane (const vbool<M>& valid_i, const Vec3vf<M>& p) const
136
{
137
const Vec3vf<M> p0p = p - p0;
138
const vfloat<M> y = dot(p0p,dP);
139
const vfloat<M> cap0 = -r0dr;
140
const vbool<M> inside_cone = y > cap0;
141
return valid_i & (p0.x != vfloat<M>(inf)) & (p1.x != vfloat<M>(inf)) & inside_cone;
142
}
143
144
/*
145
146
This function tests whether a point lies inside the capped cone
147
tangential to its ending spheres.
148
149
Therefore one has to check if the point is inside the
150
region defined by the cone clipping planes, which is
151
performed similar as in the previous function.
152
153
To perform the inside cone test we need to project the
154
point onto the line p0->p1:
155
156
dP = p1-p0
157
Y = (p-p0)*dP/length(dP)
158
159
This value Y is the distance to the projection point from
160
p0. To obtain a parameter value u going from 0 to 1 along
161
the line p0->p1 we calculate:
162
163
U = Y/length(dP)
164
165
The radii to use at points p0 and p1 are:
166
167
w0 = sr * r0
168
w1 = sr * r1
169
dw = w1-w0
170
171
Using these radii and u one can directly test if the point
172
lies inside the cone using the formula dP*dP < wy*wy with:
173
174
wy = w0 + u*dw
175
py = p0 + u*dP - p
176
177
By multiplying the calculations with length(p1-p0) and
178
inserting the definition of w can obtain simpler equations:
179
180
y = (p-p0)*dP
181
ry = r0 + y/dP^2 * dr
182
wy = sr*ry
183
py = p0 + y/dP^2*dP - p
184
y0 = - r0 * dr
185
y1 = dP^2 - r1 * dr
186
187
Thus for the in-cone test we get:
188
189
py^2 < wy^2
190
<=> py^2 < sr^2 * ry^2
191
<=> py^2 * ( dP^2 - dr^2 ) < dP^2 * ry^2
192
193
This can further get simplified to:
194
195
(p0-p)^2 * (dP^2 - dr^2) - y^2 < dP^2 * r0^2 + 2.0f*r0*dr*y;
196
197
*/
198
199
__forceinline vbool<M> isInsideCappedCone (const vbool<M>& valid_i, const Vec3vf<M>& p) const
200
{
201
const Vec3vf<M> p0p = p - p0;
202
const vfloat<M> y = dot(p0p,dP);
203
const vfloat<M> cap0 = -r0dr+vfloat<M>(ulp);
204
const vfloat<M> cap1 = -r1*dr + dPdP;
205
206
vbool<M> inside_cone = valid_i & (p0.x != vfloat<M>(inf)) & (p1.x != vfloat<M>(inf));
207
inside_cone &= y > cap0; // start clipping plane
208
inside_cone &= y < cap1; // end clipping plane
209
inside_cone &= sqr(p0p)*g - sqr(y) < dPdP * sqr_r0 + 2.0f*r0dr*y; // in cone test
210
return inside_cone;
211
}
212
213
protected:
214
Vec3vf<M> p0;
215
Vec3vf<M> p1;
216
Vec3vf<M> dP;
217
vfloat<M> dPdP;
218
vfloat<M> r0;
219
vfloat<M> sqr_r0;
220
vfloat<M> r1;
221
vfloat<M> dr;
222
vfloat<M> drdr;
223
vfloat<M> r0dr;
224
vfloat<M> g;
225
};
226
227
template<int M>
228
struct ConeGeometryIntersector : public ConeGeometry<M>
229
{
230
using ConeGeometry<M>::p0;
231
using ConeGeometry<M>::p1;
232
using ConeGeometry<M>::dP;
233
using ConeGeometry<M>::dPdP;
234
using ConeGeometry<M>::r0;
235
using ConeGeometry<M>::sqr_r0;
236
using ConeGeometry<M>::r1;
237
using ConeGeometry<M>::dr;
238
using ConeGeometry<M>::r0dr;
239
using ConeGeometry<M>::g;
240
241
ConeGeometryIntersector (const Vec3vf<M>& ray_org, const Vec3vf<M>& ray_dir, const vfloat<M>& dOdO, const vfloat<M>& rcp_dOdO, const Vec4vf<M>& a, const Vec4vf<M>& b)
242
: ConeGeometry<M>(a,b), org(ray_org), O(ray_org-p0), dO(ray_dir), dOdO(dOdO), rcp_dOdO(rcp_dOdO), OdP(dot(dP,O)), dOdP(dot(dP,dO)), yp(OdP + r0dr) {}
243
244
/*
245
246
This function intersects a ray with a cone that touches a
247
start sphere p0/r0 and end sphere p1/r1.
248
249
To find this ray/cone intersections one could just
250
calculate radii w0 and w1 as described above and use a
251
standard ray/cone intersection routine with these
252
radii. However, it turns out that calculations can get
253
simplified when deriving a specialized ray/cone
254
intersection for this special case. We perform
255
calculations relative to the cone origin p0 and define:
256
257
O = ray_org - p0
258
dO = ray_dir
259
dP = p1-p0
260
dr = r1-r0
261
dw = w1-w0
262
263
For some t we can compute the potential hit point h = O + t*dO and
264
project it onto the cone vector dP to obtain u = (h*dP)/(dP*dP). In
265
case of an intersection, the squared distance from the hit point
266
projected onto the cone center line to the hit point should be equal
267
to the squared cone radius at u:
268
269
(u*dP - h)^2 = (w0 + u*dw)^2
270
271
Inserting the definition of h, u, w0, and dw into this formula, then
272
factoring out all terms, and sorting by t^2, t^1, and t^0 terms
273
yields a quadratic equation to solve.
274
275
Inserting u:
276
( (h*dP)*dP/dP^2 - h )^2 = ( w0 + (h*dP)*dw/dP^2 )^2
277
278
Multiplying by dP^4:
279
( (h*dP)*dP - h*dP^2 )^2 = ( w0*dP^2 + (h*dP)*dw )^2
280
281
Inserting w0 and dw:
282
( (h*dP)*dP - h*dP^2 )^2 = ( r0*dP^2 + (h*dP)*dr )^2 / (1-dr^2/dP^2)
283
( (h*dP)*dP - h*dP^2 )^2 *(dP^2 - dr^2) = dP^2 * ( r0*dP^2 + (h*dP)*dr )^2
284
285
Now one can insert the definition of h, factor out, and presort by t:
286
( ((O + t*dO)*dP)*dP - (O + t*dO)*dP^2 )^2 *(dP^2 - dr^2) = dP^2 * ( r0*dP^2 + ((O + t*dO)*dP)*dr )^2
287
( (O*dP)*dP-O*dP^2 + t*( (dO*dP)*dP - dO*dP^2 ) )^2 *(dP^2 - dr^2) = dP^2 * ( r0*dP^2 + (O*dP)*dr + t*(dO*dP)*dr )^2
288
289
Factoring out further and sorting by t^2, t^1 and t^0 yields:
290
291
0 = t^2 * [ ((dO*dP)*dP - dO-dP^2)^2 * (dP^2 - dr^2) - dP^2*(dO*dP)^2*dr^2 ]
292
+ 2*t^1 * [ ((O*dP)*dP - O*dP^2) * ((dO*dP)*dP - dO*dP^2) * (dP^2 - dr^2) - dP^2*(r0*dP^2 + (O*dP)*dr)*(dO*dP)*dr ]
293
+ t^0 * [ ( (O*dP)*dP - O*dP^2)^2 * (dP^2-dr^2) - dP^2*(r0*dP^2 + (O*dP)*dr)^2 ]
294
295
This can be simplified to:
296
297
0 = t^2 * [ (dP^2 - dr^2)*dO^2 - (dO*dP)^2 ]
298
+ 2*t^1 * [ (dP^2 - dr^2)*(O*dO) - (dO*dP)*(O*dP + r0*dr) ]
299
+ t^0 * [ (dP^2 - dr^2)*O^2 - (O*dP)^2 - r0^2*dP^2 - 2.0f*r0*dr*(O*dP) ]
300
301
Solving this quadratic equation yields the values for t at which the
302
ray intersects the cone.
303
304
*/
305
306
__forceinline bool intersectCone(vbool<M>& valid, vfloat<M>& lower, vfloat<M>& upper)
307
{
308
/* return no hit by default */
309
lower = pos_inf;
310
upper = neg_inf;
311
312
/* compute quadratic equation A*t^2 + B*t + C = 0 */
313
const vfloat<M> OO = dot(O,O);
314
const vfloat<M> OdO = dot(dO,O);
315
const vfloat<M> A = g * dOdO - sqr(dOdP);
316
const vfloat<M> B = 2.0f * (g*OdO - dOdP*yp);
317
const vfloat<M> C = g*OO - sqr(OdP) - sqr_r0*dPdP - 2.0f*r0dr*OdP;
318
319
/* we miss the cone if determinant is smaller than zero */
320
const vfloat<M> D = B*B - 4.0f*A*C;
321
valid &= (D >= 0.0f & g > 0.0f); // if g <= 0 then the cone is inside a sphere end
322
323
/* When rays are parallel to the cone surface, then the
324
* ray may be inside or outside the cone. We just assume a
325
* miss in that case, which is fine as rays inside the
326
* cone would anyway hit the ending spheres in that
327
* case. */
328
valid &= abs(A) > min_rcp_input;
329
if (unlikely(none(valid))) {
330
return false;
331
}
332
333
/* compute distance to front and back hit */
334
const vfloat<M> Q = sqrt(D);
335
const vfloat<M> rcp_2A = rcp(2.0f*A);
336
t_cone_front = (-B-Q)*rcp_2A;
337
y_cone_front = yp + t_cone_front*dOdP;
338
lower = select( (y_cone_front > -(float)ulp) & (y_cone_front <= g) & (g > 0.0f), t_cone_front, vfloat<M>(pos_inf));
339
#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
340
t_cone_back = (-B+Q)*rcp_2A;
341
y_cone_back = yp + t_cone_back *dOdP;
342
upper = select( (y_cone_back > -(float)ulp) & (y_cone_back <= g) & (g > 0.0f), t_cone_back , vfloat<M>(neg_inf));
343
#endif
344
return true;
345
}
346
347
/*
348
This function intersects the ray with the end sphere at
349
p1. We already clip away hits that are inside the
350
neighboring cone segment.
351
352
*/
353
354
__forceinline void intersectEndSphere(vbool<M>& valid,
355
const ConeGeometry<M>& coneR,
356
vfloat<M>& lower, vfloat<M>& upper)
357
{
358
/* calculate front and back hit with end sphere */
359
const Vec3vf<M> O1 = org - p1;
360
const vfloat<M> O1dO = dot(O1,dO);
361
const vfloat<M> h2 = sqr(O1dO) - dOdO*(sqr(O1) - sqr(r1));
362
const vfloat<M> rhs1 = select( h2 >= 0.0f, sqrt(h2), vfloat<M>(neg_inf) );
363
364
/* clip away front hit if it is inside next cone segment */
365
t_sph1_front = (-O1dO - rhs1)*rcp_dOdO;
366
const Vec3vf<M> hit_front = org + t_sph1_front*dO;
367
vbool<M> valid_sph1_front = h2 >= 0.0f & yp + t_sph1_front*dOdP > g & !coneR.isClippedByPlane (valid, hit_front);
368
lower = select(valid_sph1_front, t_sph1_front, vfloat<M>(pos_inf));
369
370
#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
371
/* clip away back hit if it is inside next cone segment */
372
t_sph1_back = (-O1dO + rhs1)*rcp_dOdO;
373
const Vec3vf<M> hit_back = org + t_sph1_back*dO;
374
vbool<M> valid_sph1_back = h2 >= 0.0f & yp + t_sph1_back*dOdP > g & !coneR.isClippedByPlane (valid, hit_back);
375
upper = select(valid_sph1_back, t_sph1_back, vfloat<M>(neg_inf));
376
#else
377
upper = vfloat<M>(neg_inf);
378
#endif
379
}
380
381
__forceinline void intersectBeginSphere(const vbool<M>& valid,
382
vfloat<M>& lower, vfloat<M>& upper)
383
{
384
/* calculate front and back hit with end sphere */
385
const Vec3vf<M> O1 = org - p0;
386
const vfloat<M> O1dO = dot(O1,dO);
387
const vfloat<M> h2 = sqr(O1dO) - dOdO*(sqr(O1) - sqr(r0));
388
const vfloat<M> rhs1 = select( h2 >= 0.0f, sqrt(h2), vfloat<M>(neg_inf) );
389
390
/* clip away front hit if it is inside next cone segment */
391
t_sph0_front = (-O1dO - rhs1)*rcp_dOdO;
392
vbool<M> valid_sph1_front = valid & h2 >= 0.0f & yp + t_sph0_front*dOdP < 0;
393
lower = select(valid_sph1_front, t_sph0_front, vfloat<M>(pos_inf));
394
395
#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
396
/* clip away back hit if it is inside next cone segment */
397
t_sph0_back = (-O1dO + rhs1)*rcp_dOdO;
398
vbool<M> valid_sph1_back = valid & h2 >= 0.0f & yp + t_sph0_back*dOdP < 0;
399
upper = select(valid_sph1_back, t_sph0_back, vfloat<M>(neg_inf));
400
#else
401
upper = vfloat<M>(neg_inf);
402
#endif
403
}
404
405
/*
406
407
This function calculates the geometry normal of some cone hit.
408
409
For a given hit point h (relative to p0) with a cone
410
starting at p0 with radius w0 and ending at p1 with
411
radius w1 one normally calculates the geometry normal by
412
first calculating the parmetric u hit location along the
413
cone:
414
415
u = dot(h,dP)/dP^2
416
417
Using this value one can now directly calculate the
418
geometry normal by bending the connection vector (h-u*dP)
419
from hit to projected hit with some cone dependent value
420
dw/sqrt(dP^2) * normalize(dP):
421
422
Ng = normalize(h-u*dP) - dw/length(dP) * normalize(dP)
423
424
The length of the vector (h-u*dP) can also get calculated
425
by interpolating the radii as w0+u*dw which yields:
426
427
Ng = (h-u*dP)/(w0+u*dw) - dw/dP^2 * dP
428
429
Multiplying with (w0+u*dw) yield a scaled Ng':
430
431
Ng' = (h-u*dP) - (w0+u*dw)*dw/dP^2*dP
432
433
Inserting the definition of w0 and dw and refactoring
434
yield a further scaled Ng'':
435
436
Ng'' = (dP^2 - dr^2) (h-q) - (r0+u*dr)*dr*dP
437
438
Now inserting the definition of u gives and multiplying
439
with the denominator yields:
440
441
Ng''' = (dP^2-dr^2)*(dP^2*h-dot(h,dP)*dP) - (dP^2*r0+dot(h,dP)*dr)*dr*dP
442
443
Factoring out, cancelling terms, dividing by dP^2, and
444
factoring again yields finally:
445
446
Ng'''' = (dP^2-dr^2)*h - dP*(dot(h,dP) + r0*dr)
447
448
*/
449
450
__forceinline Vec3vf<M> Ng_cone(const vbool<M>& front_hit) const
451
{
452
#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
453
const vfloat<M> y = select(front_hit, y_cone_front, y_cone_back);
454
const vfloat<M> t = select(front_hit, t_cone_front, t_cone_back);
455
const Vec3vf<M> h = O + t*dO;
456
return g*h-dP*y;
457
#else
458
const Vec3vf<M> h = O + t_cone_front*dO;
459
return g*h-dP*y_cone_front;
460
#endif
461
}
462
463
/* compute geometry normal of sphere hit as the difference
464
* vector from hit point to sphere center */
465
466
__forceinline Vec3vf<M> Ng_sphere1(const vbool<M>& front_hit) const
467
{
468
#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
469
const vfloat<M> t_sph1 = select(front_hit, t_sph1_front, t_sph1_back);
470
return org+t_sph1*dO-p1;
471
#else
472
return org+t_sph1_front*dO-p1;
473
#endif
474
}
475
476
__forceinline Vec3vf<M> Ng_sphere0(const vbool<M>& front_hit) const
477
{
478
#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
479
const vfloat<M> t_sph0 = select(front_hit, t_sph0_front, t_sph0_back);
480
return org+t_sph0*dO-p0;
481
#else
482
return org+t_sph0_front*dO-p0;
483
#endif
484
}
485
486
/*
487
This function calculates the u coordinate of a
488
hit. Therefore we use the hit distance y (which is zero
489
at the first cone clipping plane) and divide by distance
490
g between the clipping planes.
491
492
*/
493
494
__forceinline vfloat<M> u_cone(const vbool<M>& front_hit) const
495
{
496
#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
497
const vfloat<M> y = select(front_hit, y_cone_front, y_cone_back);
498
return clamp(y*rcp(g));
499
#else
500
return clamp(y_cone_front*rcp(g));
501
#endif
502
}
503
504
private:
505
Vec3vf<M> org;
506
Vec3vf<M> O;
507
Vec3vf<M> dO;
508
vfloat<M> dOdO;
509
vfloat<M> rcp_dOdO;
510
vfloat<M> OdP;
511
vfloat<M> dOdP;
512
513
/* for ray/cone intersection */
514
private:
515
vfloat<M> yp;
516
vfloat<M> y_cone_front;
517
vfloat<M> t_cone_front;
518
#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
519
vfloat<M> y_cone_back;
520
vfloat<M> t_cone_back;
521
#endif
522
523
/* for ray/sphere intersection */
524
private:
525
vfloat<M> t_sph1_front;
526
vfloat<M> t_sph0_front;
527
#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
528
vfloat<M> t_sph1_back;
529
vfloat<M> t_sph0_back;
530
#endif
531
};
532
533
534
template<int M, typename Epilog, typename ray_tfar_func>
535
static __forceinline bool intersectConeSphere(const vbool<M>& valid_i,
536
const Vec3vf<M>& ray_org_in, const Vec3vf<M>& ray_dir,
537
const vfloat<M>& ray_tnear, const ray_tfar_func& ray_tfar,
538
const Vec4vf<M>& v0, const Vec4vf<M>& v1,
539
const Vec4vf<M>& vL, const Vec4vf<M>& vR,
540
const Epilog& epilog)
541
{
542
vbool<M> valid = valid_i;
543
544
/* move ray origin closer to make calculations numerically stable */
545
const vfloat<M> dOdO = sqr(ray_dir);
546
const vfloat<M> rcp_dOdO = rcp(dOdO);
547
const Vec3vf<M> center = vfloat<M>(0.5f)*(v0.xyz()+v1.xyz());
548
const vfloat<M> dt = dot(center-ray_org_in,ray_dir)*rcp_dOdO;
549
const Vec3vf<M> ray_org = ray_org_in + dt*ray_dir;
550
551
/* intersect with cone from v0 to v1 */
552
vfloat<M> t_cone_lower, t_cone_upper;
553
ConeGeometryIntersector<M> cone (ray_org, ray_dir, dOdO, rcp_dOdO, v0, v1);
554
vbool<M> validCone = valid;
555
cone.intersectCone(validCone, t_cone_lower, t_cone_upper);
556
557
valid &= (validCone | (cone.g <= 0.0f)); // if cone is entirely in sphere end - check sphere
558
if (unlikely(none(valid)))
559
return false;
560
561
/* cone hits inside the neighboring capped cones are inside the geometry and thus ignored */
562
const ConeGeometry<M> coneL (v0, vL);
563
const ConeGeometry<M> coneR (v1, vR);
564
#if !defined(EMBREE_BACKFACE_CULLING_CURVES)
565
const Vec3vf<M> hit_lower = ray_org + t_cone_lower*ray_dir;
566
const Vec3vf<M> hit_upper = ray_org + t_cone_upper*ray_dir;
567
t_cone_lower = select (!coneL.isInsideCappedCone (validCone, hit_lower) & !coneR.isInsideCappedCone (validCone, hit_lower), t_cone_lower, vfloat<M>(pos_inf));
568
t_cone_upper = select (!coneL.isInsideCappedCone (validCone, hit_upper) & !coneR.isInsideCappedCone (validCone, hit_upper), t_cone_upper, vfloat<M>(neg_inf));
569
#endif
570
571
/* intersect ending sphere */
572
vfloat<M> t_sph1_lower, t_sph1_upper;
573
vfloat<M> t_sph0_lower = vfloat<M>(pos_inf);
574
vfloat<M> t_sph0_upper = vfloat<M>(neg_inf);
575
cone.intersectEndSphere(valid, coneR, t_sph1_lower, t_sph1_upper);
576
577
const vbool<M> isBeginPoint = valid & (vL[0] == vfloat<M>(pos_inf));
578
if (unlikely(any(isBeginPoint))) {
579
cone.intersectBeginSphere (isBeginPoint, t_sph0_lower, t_sph0_upper);
580
}
581
582
/* CSG union of cone and end sphere */
583
vfloat<M> t_sph_lower = min(t_sph0_lower, t_sph1_lower);
584
vfloat<M> t_cone_sphere_lower = min(t_cone_lower, t_sph_lower);
585
#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
586
vfloat<M> t_sph_upper = max(t_sph0_upper, t_sph1_upper);
587
vfloat<M> t_cone_sphere_upper = max(t_cone_upper, t_sph_upper);
588
589
/* filter out hits that are not in tnear/tfar range */
590
const vbool<M> valid_lower = valid & ray_tnear <= dt+t_cone_sphere_lower & dt+t_cone_sphere_lower <= ray_tfar() & t_cone_sphere_lower != vfloat<M>(pos_inf);
591
const vbool<M> valid_upper = valid & ray_tnear <= dt+t_cone_sphere_upper & dt+t_cone_sphere_upper <= ray_tfar() & t_cone_sphere_upper != vfloat<M>(neg_inf);
592
593
/* check if there is a first hit */
594
const vbool<M> valid_first = valid_lower | valid_upper;
595
if (unlikely(none(valid_first)))
596
return false;
597
598
/* construct first hit */
599
const vfloat<M> t_first = select(valid_lower, t_cone_sphere_lower, t_cone_sphere_upper);
600
const vbool<M> cone_hit_first = t_first == t_cone_lower | t_first == t_cone_upper;
601
const vbool<M> sph0_hit_first = t_first == t_sph0_lower | t_first == t_sph0_upper;
602
const Vec3vf<M> Ng_first = select(cone_hit_first, cone.Ng_cone(valid_lower), select (sph0_hit_first, cone.Ng_sphere0(valid_lower), cone.Ng_sphere1(valid_lower)));
603
const vfloat<M> u_first = select(cone_hit_first, cone.u_cone(valid_lower), select (sph0_hit_first, vfloat<M>(zero), vfloat<M>(one)));
604
605
/* invoke intersection filter for first hit */
606
RoundLineIntersectorHitM<M> hit(u_first,zero,dt+t_first,Ng_first);
607
const bool is_hit_first = epilog(valid_first, hit);
608
609
/* check for possible second hits before potentially accepted hit */
610
const vfloat<M> t_second = t_cone_sphere_upper;
611
const vbool<M> valid_second = valid_lower & valid_upper & (dt+t_cone_sphere_upper <= ray_tfar());
612
if (unlikely(none(valid_second)))
613
return is_hit_first;
614
615
/* invoke intersection filter for second hit */
616
const vbool<M> cone_hit_second = t_second == t_cone_lower | t_second == t_cone_upper;
617
const vbool<M> sph0_hit_second = t_second == t_sph0_lower | t_second == t_sph0_upper;
618
const Vec3vf<M> Ng_second = select(cone_hit_second, cone.Ng_cone(false), select (sph0_hit_second, cone.Ng_sphere0(false), cone.Ng_sphere1(false)));
619
const vfloat<M> u_second = select(cone_hit_second, cone.u_cone(false), select (sph0_hit_second, vfloat<M>(zero), vfloat<M>(one)));
620
621
hit = RoundLineIntersectorHitM<M>(u_second,zero,dt+t_second,Ng_second);
622
const bool is_hit_second = epilog(valid_second, hit);
623
624
return is_hit_first | is_hit_second;
625
#else
626
/* filter out hits that are not in tnear/tfar range */
627
const vbool<M> valid_lower = valid & ray_tnear <= dt+t_cone_sphere_lower & dt+t_cone_sphere_lower <= ray_tfar() & t_cone_sphere_lower != vfloat<M>(pos_inf);
628
629
/* check if there is a valid hit */
630
if (unlikely(none(valid_lower)))
631
return false;
632
633
/* construct first hit */
634
const vbool<M> cone_hit_first = t_cone_sphere_lower == t_cone_lower | t_cone_sphere_lower == t_cone_upper;
635
const vbool<M> sph0_hit_first = t_cone_sphere_lower == t_sph0_lower | t_cone_sphere_lower == t_sph0_upper;
636
const Vec3vf<M> Ng_first = select(cone_hit_first, cone.Ng_cone(valid_lower), select (sph0_hit_first, cone.Ng_sphere0(valid_lower), cone.Ng_sphere1(valid_lower)));
637
const vfloat<M> u_first = select(cone_hit_first, cone.u_cone(valid_lower), select (sph0_hit_first, vfloat<M>(zero), vfloat<M>(one)));
638
639
/* invoke intersection filter for first hit */
640
RoundLineIntersectorHitM<M> hit(u_first,zero,dt+t_cone_sphere_lower,Ng_first);
641
const bool is_hit_first = epilog(valid_lower, hit);
642
643
return is_hit_first;
644
#endif
645
}
646
647
} // end namespace __roundline_internal
648
649
template<int M>
650
struct RoundLinearCurveIntersector1
651
{
652
typedef CurvePrecalculations1 Precalculations;
653
654
template<typename Ray>
655
struct ray_tfar {
656
Ray& ray;
657
__forceinline ray_tfar(Ray& ray) : ray(ray) {}
658
__forceinline vfloat<M> operator() () const { return ray.tfar; };
659
};
660
661
template<typename Ray, typename Epilog>
662
static __forceinline bool intersect(const vbool<M>& valid_i,
663
Ray& ray,
664
RayQueryContext* context,
665
const LineSegments* geom,
666
const Precalculations& pre,
667
const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
668
const Vec4vf<M>& vLi, const Vec4vf<M>& vRi,
669
const Epilog& epilog)
670
{
671
const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
672
const Vec3vf<M> ray_dir(ray.dir.x, ray.dir.y, ray.dir.z);
673
const vfloat<M> ray_tnear(ray.tnear());
674
const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
675
const Vec4vf<M> v1 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v1i);
676
const Vec4vf<M> vL = enlargeRadiusToMinWidth<M>(context,geom,ray_org,vLi);
677
const Vec4vf<M> vR = enlargeRadiusToMinWidth<M>(context,geom,ray_org,vRi);
678
return __roundline_internal::intersectConeSphere<M>(valid_i,ray_org,ray_dir,ray_tnear,ray_tfar<Ray>(ray),v0,v1,vL,vR,epilog);
679
}
680
};
681
682
template<int M, int K>
683
struct RoundLinearCurveIntersectorK
684
{
685
typedef CurvePrecalculationsK<K> Precalculations;
686
687
struct ray_tfar {
688
RayK<K>& ray;
689
size_t k;
690
__forceinline ray_tfar(RayK<K>& ray, size_t k) : ray(ray), k(k) {}
691
__forceinline vfloat<M> operator() () const { return ray.tfar[k]; };
692
};
693
694
template<typename Epilog>
695
static __forceinline bool intersect(const vbool<M>& valid_i,
696
RayK<K>& ray, size_t k,
697
RayQueryContext* context,
698
const LineSegments* geom,
699
const Precalculations& pre,
700
const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,
701
const Vec4vf<M>& vLi, const Vec4vf<M>& vRi,
702
const Epilog& epilog)
703
{
704
const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
705
const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
706
const vfloat<M> ray_tnear = ray.tnear()[k];
707
const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
708
const Vec4vf<M> v1 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v1i);
709
const Vec4vf<M> vL = enlargeRadiusToMinWidth<M>(context,geom,ray_org,vLi);
710
const Vec4vf<M> vR = enlargeRadiusToMinWidth<M>(context,geom,ray_org,vRi);
711
return __roundline_internal::intersectConeSphere<M>(valid_i,ray_org,ray_dir,ray_tnear,ray_tfar(ray,k),v0,v1,vL,vR,epilog);
712
}
713
};
714
}
715
}
716
717