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 "../common/scene_points.h"
8#include "curve_intersector_precalculations.h"
9
10namespace embree
11{
12 namespace isa
13 {
14 template<int M>
15 struct DiscIntersectorHitM
16 {
17 __forceinline DiscIntersectorHitM() {}
18
19 __forceinline DiscIntersectorHitM(const vfloat<M>& u, const vfloat<M>& v, const vfloat<M>& t, const Vec3vf<M>& Ng)
20 : vu(u), vv(v), vt(t), vNg(Ng)
21 {
22 }
23
24 __forceinline void finalize() {}
25
26 __forceinline Vec2f uv(const size_t i) const
27 {
28 return Vec2f(vu[i], vv[i]);
29 }
30 __forceinline float t(const size_t i) const
31 {
32 return vt[i];
33 }
34 __forceinline Vec3fa Ng(const size_t i) const
35 {
36 return Vec3fa(vNg.x[i], vNg.y[i], vNg.z[i]);
37 }
38
39 public:
40 vfloat<M> vu;
41 vfloat<M> vv;
42 vfloat<M> vt;
43 Vec3vf<M> vNg;
44 };
45
46 template<int M>
47 struct DiscIntersector1
48 {
49 typedef CurvePrecalculations1 Precalculations;
50
51 template<typename Epilog>
52 static __forceinline bool intersect(
53 const vbool<M>& valid_i,
54 Ray& ray,
55 IntersectContext* context,
56 const Points* geom,
57 const Precalculations& pre,
58 const Vec4vf<M>& v0i,
59 const Epilog& epilog)
60 {
61 vbool<M> valid = valid_i;
62
63 const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
64 const Vec3vf<M> ray_dir(ray.dir.x, ray.dir.y, ray.dir.z);
65 const vfloat<M> rd2 = rcp(dot(ray_dir, ray_dir));
66
67 const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
68 const Vec3vf<M> center = v0.xyz();
69 const vfloat<M> radius = v0.w;
70
71 /* compute ray distance projC0 to hit point with ray oriented plane */
72 const Vec3vf<M> c0 = center - ray_org;
73 const vfloat<M> projC0 = dot(c0, ray_dir) * rd2;
74
75 valid &= (vfloat<M>(ray.tnear()) <= projC0) & (projC0 <= vfloat<M>(ray.tfar));
76 if (unlikely(none(valid)))
77 return false;
78
79 /* check if hit point lies inside disc */
80 const Vec3vf<M> perp = c0 - projC0 * ray_dir;
81 const vfloat<M> l2 = dot(perp, perp);
82 const vfloat<M> r2 = radius * radius;
83 valid &= (l2 <= r2);
84 if (unlikely(none(valid)))
85 return false;
86
87 /* We reject hits where the ray origin lies inside the ray
88 * oriented disc to avoid self intersections. */
89#if defined(EMBREE_DISC_POINT_SELF_INTERSECTION_AVOIDANCE)
90 const vfloat<M> m2 = dot(c0, c0);
91 valid &= (m2 > r2);
92 if (unlikely(none(valid)))
93 return false;
94#endif
95
96 DiscIntersectorHitM<M> hit(zero, zero, projC0, -ray_dir);
97 return epilog(valid, hit);
98 }
99
100 template<typename Epilog>
101 static __forceinline bool intersect(const vbool<M>& valid_i,
102 Ray& ray,
103 IntersectContext* context,
104 const Points* geom,
105 const Precalculations& pre,
106 const Vec4vf<M>& v0i,
107 const Vec3vf<M>& normal,
108 const Epilog& epilog)
109 {
110 vbool<M> valid = valid_i;
111 const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);
112
113 const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
114 const Vec3vf<M> center = v0.xyz();
115 const vfloat<M> radius = v0.w;
116
117 vfloat<M> divisor = dot(Vec3vf<M>((Vec3fa)ray.dir), normal);
118 const vbool<M> parallel = divisor == vfloat<M>(0.f);
119 valid &= !parallel;
120 divisor = select(parallel, 1.f, divisor); // prevent divide by zero
121
122 vfloat<M> t = dot(center - Vec3vf<M>((Vec3fa)ray.org), Vec3vf<M>(normal)) / divisor;
123
124 valid &= (vfloat<M>(ray.tnear()) <= t) & (t <= vfloat<M>(ray.tfar));
125 if (unlikely(none(valid)))
126 return false;
127
128 Vec3vf<M> intersection = Vec3vf<M>((Vec3fa)ray.org) + Vec3vf<M>((Vec3fa)ray.dir) * t;
129 vfloat<M> dist2 = dot(intersection - center, intersection - center);
130 valid &= dist2 < radius * radius;
131 if (unlikely(none(valid)))
132 return false;
133
134 DiscIntersectorHitM<M> hit(zero, zero, t, normal);
135 return epilog(valid, hit);
136 }
137 };
138
139 template<int M, int K>
140 struct DiscIntersectorK
141 {
142 typedef CurvePrecalculationsK<K> Precalculations;
143
144 template<typename Epilog>
145 static __forceinline bool intersect(const vbool<M>& valid_i,
146 RayK<K>& ray,
147 size_t k,
148 IntersectContext* context,
149 const Points* geom,
150 const Precalculations& pre,
151 const Vec4vf<M>& v0i,
152 const Epilog& epilog)
153 {
154 vbool<M> valid = valid_i;
155
156 const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
157 const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
158 const vfloat<M> rd2 = rcp(dot(ray_dir, ray_dir));
159
160 const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
161 const Vec3vf<M> center = v0.xyz();
162 const vfloat<M> radius = v0.w;
163
164 /* compute ray distance projC0 to hit point with ray oriented plane */
165 const Vec3vf<M> c0 = center - ray_org;
166 const vfloat<M> projC0 = dot(c0, ray_dir) * rd2;
167
168 valid &= (vfloat<M>(ray.tnear()[k]) <= projC0) & (projC0 <= vfloat<M>(ray.tfar[k]));
169 if (unlikely(none(valid)))
170 return false;
171
172 /* check if hit point lies inside disc */
173 const Vec3vf<M> perp = c0 - projC0 * ray_dir;
174 const vfloat<M> l2 = dot(perp, perp);
175 const vfloat<M> r2 = radius * radius;
176 valid &= (l2 <= r2);
177 if (unlikely(none(valid)))
178 return false;
179
180 /* We reject hits where the ray origin lies inside the ray
181 * oriented disc to avoid self intersections. */
182#if defined(EMBREE_DISC_POINT_SELF_INTERSECTION_AVOIDANCE)
183 const vfloat<M> m2 = dot(c0, c0);
184 valid &= (m2 > r2);
185 if (unlikely(none(valid)))
186 return false;
187#endif
188
189 DiscIntersectorHitM<M> hit(zero, zero, projC0, -ray_dir);
190 return epilog(valid, hit);
191 }
192
193 template<typename Epilog>
194 static __forceinline bool intersect(const vbool<M>& valid_i,
195 RayK<K>& ray,
196 size_t k,
197 IntersectContext* context,
198 const Points* geom,
199 const Precalculations& pre,
200 const Vec4vf<M>& v0i,
201 const Vec3vf<M>& normal,
202 const Epilog& epilog)
203 {
204 vbool<M> valid = valid_i;
205 const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);
206 const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);
207
208 const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);
209 const Vec3vf<M> center = v0.xyz();
210 const vfloat<M> radius = v0.w;
211
212 vfloat<M> divisor = dot(Vec3vf<M>(ray_dir), normal);
213 const vbool<M> parallel = divisor == vfloat<M>(0.f);
214 valid &= !parallel;
215 divisor = select(parallel, 1.f, divisor); // prevent divide by zero
216
217 vfloat<M> t = dot(center - Vec3vf<M>(ray_org), Vec3vf<M>(normal)) / divisor;
218
219 valid &= (vfloat<M>(ray.tnear()[k]) <= t) & (t <= vfloat<M>(ray.tfar[k]));
220 if (unlikely(none(valid)))
221 return false;
222
223 Vec3vf<M> intersection = Vec3vf<M>(ray_org) + Vec3vf<M>(ray_dir) * t;
224 vfloat<M> dist2 = dot(intersection - center, intersection - center);
225 valid &= dist2 < radius * radius;
226 if (unlikely(none(valid)))
227 return false;
228
229 DiscIntersectorHitM<M> hit(zero, zero, t, normal);
230 return epilog(valid, hit);
231 }
232 };
233 } // namespace isa
234} // namespace embree
235