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 "quad_intersector.h"
8#include "curve_intersector_precalculations.h"
9
10#define Bezier1Intersector1 RibbonCurve1Intersector1
11#define Bezier1IntersectorK RibbonCurve1IntersectorK
12
13namespace embree
14{
15 namespace isa
16 {
17 template<typename NativeCurve3ff, int M>
18 struct RibbonHit
19 {
20 __forceinline RibbonHit() {}
21
22 __forceinline RibbonHit(const vbool<M>& valid, const vfloat<M>& U, const vfloat<M>& V, const vfloat<M>& T, const int i, const int N,
23 const NativeCurve3ff& curve3D)
24 : U(U), V(V), T(T), i(i), N(N), curve3D(curve3D), valid(valid) {}
25
26 __forceinline void finalize()
27 {
28 vu = (vfloat<M>(step)+U+vfloat<M>(float(i)))*(1.0f/float(N));
29 vv = V;
30 vt = T;
31 }
32
33 __forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }
34 __forceinline float t (const size_t i) const { return vt[i]; }
35 __forceinline Vec3fa Ng(const size_t i) const { return curve3D.eval_du(vu[i]); }
36
37 __forceinline Vec2vf<M> uv() const { return Vec2vf<M>(vu,vv); }
38 __forceinline vfloat<M> t () const { return vt; }
39 __forceinline Vec3vf<M> Ng() const { return (Vec3vf<M>) curve3D.template veval_du<M>(vu); }
40
41 public:
42 vfloat<M> U;
43 vfloat<M> V;
44 vfloat<M> T;
45 int i, N;
46 NativeCurve3ff curve3D;
47
48 public:
49 vbool<M> valid;
50 vfloat<M> vu;
51 vfloat<M> vv;
52 vfloat<M> vt;
53 };
54
55 /* calculate squared distance of point p0 to line p1->p2 */
56 __forceinline std::pair<vfloatx,vfloatx> sqr_point_line_distance(const Vec2vfx& p0, const Vec2vfx& p1, const Vec2vfx& p2)
57 {
58 const vfloatx num = det(p2-p1,p1-p0);
59 const vfloatx den2 = dot(p2-p1,p2-p1);
60 return std::make_pair(num*num,den2);
61 }
62
63 /* performs culling against a cylinder */
64 __forceinline vboolx cylinder_culling_test(const Vec2vfx& p0, const Vec2vfx& p1, const Vec2vfx& p2, const vfloatx& r)
65 {
66 const std::pair<vfloatx,vfloatx> d = sqr_point_line_distance(p0,p1,p2);
67 return d.first <= r*r*d.second;
68 }
69
70 template<typename NativeCurve3ff, typename Epilog>
71 __forceinline bool intersect_ribbon(const Vec3fa& ray_org, const Vec3fa& ray_dir, const float ray_tnear, const float& ray_tfar,
72 const LinearSpace3fa& ray_space, const float& depth_scale,
73 const NativeCurve3ff& curve3D, const int N,
74 const Epilog& epilog)
75 {
76 /* transform control points into ray space */
77 const NativeCurve3ff curve2D = curve3D.xfm_pr(ray_space,ray_org);
78 float eps = 4.0f*float(ulp)*reduce_max(max(abs(curve2D.v0),abs(curve2D.v1),abs(curve2D.v2),abs(curve2D.v3)));
79
80 /* evaluate the bezier curve */
81 bool ishit = false;
82 vboolx valid = vfloatx(step) < vfloatx(float(N));
83 const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(0,N);
84 const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(0,N);
85 valid &= cylinder_culling_test(zero,Vec2vfx(p0.x,p0.y),Vec2vfx(p1.x,p1.y),max(p0.w,p1.w));
86
87 if (any(valid))
88 {
89 Vec3vfx dp0dt = curve2D.template derivative0<VSIZEX>(0,N);
90 Vec3vfx dp1dt = curve2D.template derivative1<VSIZEX>(0,N);
91 dp0dt = select(reduce_max(abs(dp0dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp0dt);
92 dp1dt = select(reduce_max(abs(dp1dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp1dt);
93 const Vec3vfx n0(dp0dt.y,-dp0dt.x,0.0f);
94 const Vec3vfx n1(dp1dt.y,-dp1dt.x,0.0f);
95 const Vec3vfx nn0 = normalize(n0);
96 const Vec3vfx nn1 = normalize(n1);
97 const Vec3vfx lp0 = madd(p0.w,nn0,Vec3vfx(p0));
98 const Vec3vfx lp1 = madd(p1.w,nn1,Vec3vfx(p1));
99 const Vec3vfx up0 = nmadd(p0.w,nn0,Vec3vfx(p0));
100 const Vec3vfx up1 = nmadd(p1.w,nn1,Vec3vfx(p1));
101
102 vfloatx vu,vv,vt;
103 vboolx valid0 = intersect_quad_backface_culling<VSIZEX>(valid,zero,Vec3fa(0,0,1),ray_tnear,ray_tfar,lp0,lp1,up1,up0,vu,vv,vt);
104
105 if (any(valid0))
106 {
107 /* ignore self intersections */
108 if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f) {
109 vfloatx r = lerp(p0.w, p1.w, vu);
110 valid0 &= vt > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale;
111 }
112
113 if (any(valid0))
114 {
115 vv = madd(2.0f,vv,vfloatx(-1.0f));
116 RibbonHit<NativeCurve3ff,VSIZEX> bhit(valid0,vu,vv,vt,0,N,curve3D);
117 ishit |= epilog(bhit.valid,bhit);
118 }
119 }
120 }
121
122 if (unlikely(VSIZEX < N))
123 {
124 /* process SIMD-size many segments per iteration */
125 for (int i=VSIZEX; i<N; i+=VSIZEX)
126 {
127 /* evaluate the bezier curve */
128 vboolx valid = vintx(i)+vintx(step) < vintx(N);
129 const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(i,N);
130 const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(i,N);
131 valid &= cylinder_culling_test(zero,Vec2vfx(p0.x,p0.y),Vec2vfx(p1.x,p1.y),max(p0.w,p1.w));
132 if (none(valid)) continue;
133
134 Vec3vfx dp0dt = curve2D.template derivative0<VSIZEX>(i,N);
135 Vec3vfx dp1dt = curve2D.template derivative1<VSIZEX>(i,N);
136 dp0dt = select(reduce_max(abs(dp0dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp0dt);
137 dp1dt = select(reduce_max(abs(dp1dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp1dt);
138 const Vec3vfx n0(dp0dt.y,-dp0dt.x,0.0f);
139 const Vec3vfx n1(dp1dt.y,-dp1dt.x,0.0f);
140 const Vec3vfx nn0 = normalize(n0);
141 const Vec3vfx nn1 = normalize(n1);
142 const Vec3vfx lp0 = madd(p0.w,nn0,Vec3vfx(p0));
143 const Vec3vfx lp1 = madd(p1.w,nn1,Vec3vfx(p1));
144 const Vec3vfx up0 = nmadd(p0.w,nn0,Vec3vfx(p0));
145 const Vec3vfx up1 = nmadd(p1.w,nn1,Vec3vfx(p1));
146
147 vfloatx vu,vv,vt;
148 vboolx valid0 = intersect_quad_backface_culling<VSIZEX>(valid,zero,Vec3fa(0,0,1),ray_tnear,ray_tfar,lp0,lp1,up1,up0,vu,vv,vt);
149
150 if (any(valid0))
151 {
152 /* ignore self intersections */
153 if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f) {
154 vfloatx r = lerp(p0.w, p1.w, vu);
155 valid0 &= vt > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale;
156 }
157
158 if (any(valid0))
159 {
160 vv = madd(2.0f,vv,vfloatx(-1.0f));
161 RibbonHit<NativeCurve3ff,VSIZEX> bhit(valid0,vu,vv,vt,i,N,curve3D);
162 ishit |= epilog(bhit.valid,bhit);
163 }
164 }
165 }
166 }
167 return ishit;
168 }
169
170 template<template<typename Ty> class NativeCurve>
171 struct RibbonCurve1Intersector1
172 {
173 typedef NativeCurve<Vec3ff> NativeCurve3ff;
174
175 template<typename Epilog>
176 __forceinline bool intersect(const CurvePrecalculations1& pre, Ray& ray,
177 IntersectContext* context,
178 const CurveGeometry* geom, const unsigned int primID,
179 const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3,
180 const Epilog& epilog)
181 {
182 const int N = geom->tessellationRate;
183 NativeCurve3ff curve(v0,v1,v2,v3);
184 curve = enlargeRadiusToMinWidth(context,geom,ray.org,curve);
185 return intersect_ribbon<NativeCurve3ff>(ray.org,ray.dir,ray.tnear(),ray.tfar,
186 pre.ray_space,pre.depth_scale,
187 curve,N,
188 epilog);
189 }
190 };
191
192 template<template<typename Ty> class NativeCurve, int K>
193 struct RibbonCurve1IntersectorK
194 {
195 typedef NativeCurve<Vec3ff> NativeCurve3ff;
196
197 template<typename Epilog>
198 __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& ray, size_t k,
199 IntersectContext* context,
200 const CurveGeometry* geom, const unsigned int primID,
201 const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3,
202 const Epilog& epilog)
203 {
204 const int N = geom->tessellationRate;
205 const Vec3fa ray_org(ray.org.x[k],ray.org.y[k],ray.org.z[k]);
206 const Vec3fa ray_dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]);
207 NativeCurve3ff curve(v0,v1,v2,v3);
208 curve = enlargeRadiusToMinWidth(context,geom,ray_org,curve);
209 return intersect_ribbon<NativeCurve3ff>(ray_org,ray_dir,ray.tnear()[k],ray.tfar[k],
210 pre.ray_space[k],pre.depth_scale[k],
211 curve,N,
212 epilog);
213 }
214 };
215 }
216}
217