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 | |
10 | namespace 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 | |