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 SphereIntersectorHitM |
16 | { |
17 | __forceinline SphereIntersectorHitM() {} |
18 | |
19 | __forceinline SphereIntersectorHitM(const vfloat<M>& t, const Vec3vf<M>& Ng) |
20 | : vt(t), vNg(Ng) {} |
21 | |
22 | __forceinline void finalize() {} |
23 | |
24 | __forceinline Vec2f uv(const size_t i) const { |
25 | return Vec2f(0.0f, 0.0f); |
26 | } |
27 | __forceinline float t(const size_t i) const { |
28 | return vt[i]; |
29 | } |
30 | __forceinline Vec3fa Ng(const size_t i) const { |
31 | return Vec3fa(vNg.x[i], vNg.y[i], vNg.z[i]); |
32 | } |
33 | |
34 | public: |
35 | vfloat<M> vt; |
36 | Vec3vf<M> vNg; |
37 | }; |
38 | |
39 | template<int M> |
40 | struct SphereIntersector1 |
41 | { |
42 | typedef CurvePrecalculations1 Precalculations; |
43 | |
44 | template<typename Epilog> |
45 | static __forceinline bool intersect( |
46 | const vbool<M>& valid_i, Ray& ray, |
47 | const Precalculations& pre, const Vec4vf<M>& v0, const Epilog& epilog) |
48 | { |
49 | vbool<M> valid = valid_i; |
50 | |
51 | const vfloat<M> rd2 = rcp(dot(ray.dir, ray.dir)); |
52 | const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z); |
53 | const Vec3vf<M> ray_dir(ray.dir.x, ray.dir.y, ray.dir.z); |
54 | const Vec3vf<M> center = v0.xyz(); |
55 | const vfloat<M> radius = v0.w; |
56 | |
57 | const Vec3vf<M> c0 = center - ray_org; |
58 | const vfloat<M> projC0 = dot(c0, ray_dir) * rd2; |
59 | const Vec3vf<M> perp = c0 - projC0 * ray_dir; |
60 | const vfloat<M> l2 = dot(perp, perp); |
61 | const vfloat<M> r2 = radius * radius; |
62 | valid &= (l2 <= r2); |
63 | if (unlikely(none(valid))) |
64 | return false; |
65 | |
66 | const vfloat<M> td = sqrt((r2 - l2) * rd2); |
67 | const vfloat<M> t_front = projC0 - td; |
68 | const vfloat<M> t_back = projC0 + td; |
69 | |
70 | const vbool<M> valid_front = valid & (ray.tnear() <= t_front) & (t_front <= ray.tfar); |
71 | const vbool<M> valid_back = valid & (ray.tnear() <= t_back ) & (t_back <= ray.tfar); |
72 | |
73 | /* check if there is a first hit */ |
74 | const vbool<M> valid_first = valid_front | valid_back; |
75 | if (unlikely(none(valid_first))) |
76 | return false; |
77 | |
78 | /* construct first hit */ |
79 | const vfloat<M> td_front = -td; |
80 | const vfloat<M> td_back = +td; |
81 | const vfloat<M> t_first = select(valid_front, t_front, t_back); |
82 | const Vec3vf<M> Ng_first = select(valid_front, td_front, td_back) * ray_dir - perp; |
83 | SphereIntersectorHitM<M> hit(t_first, Ng_first); |
84 | |
85 | /* invoke intersection filter for first hit */ |
86 | const bool is_hit_first = epilog(valid_first, hit); |
87 | |
88 | /* check for possible second hits before potentially accepted hit */ |
89 | const vfloat<M> t_second = t_back; |
90 | const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar); |
91 | if (unlikely(none(valid_second))) |
92 | return is_hit_first; |
93 | |
94 | /* invoke intersection filter for second hit */ |
95 | const Vec3vf<M> Ng_second = td_back * ray_dir - perp; |
96 | hit = SphereIntersectorHitM<M> (t_second, Ng_second); |
97 | const bool is_hit_second = epilog(valid_second, hit); |
98 | |
99 | return is_hit_first | is_hit_second; |
100 | } |
101 | |
102 | template<typename Epilog> |
103 | static __forceinline bool intersect( |
104 | const vbool<M>& valid_i, Ray& ray, IntersectContext* context, const Points* geom, |
105 | const Precalculations& pre, const Vec4vf<M>& v0i, const Epilog& epilog) |
106 | { |
107 | const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z); |
108 | const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i); |
109 | return intersect(valid_i,ray,pre,v0,epilog); |
110 | } |
111 | }; |
112 | |
113 | template<int M, int K> |
114 | struct SphereIntersectorK |
115 | { |
116 | typedef CurvePrecalculationsK<K> Precalculations; |
117 | |
118 | template<typename Epilog> |
119 | static __forceinline bool intersect(const vbool<M>& valid_i, |
120 | RayK<K>& ray, size_t k, |
121 | IntersectContext* context, |
122 | const Points* geom, |
123 | const Precalculations& pre, |
124 | const Vec4vf<M>& v0i, |
125 | const Epilog& epilog) |
126 | { |
127 | vbool<M> valid = valid_i; |
128 | |
129 | const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]); |
130 | const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]); |
131 | const vfloat<M> rd2 = rcp(dot(ray_dir, ray_dir)); |
132 | |
133 | const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i); |
134 | const Vec3vf<M> center = v0.xyz(); |
135 | const vfloat<M> radius = v0.w; |
136 | |
137 | const Vec3vf<M> c0 = center - ray_org; |
138 | const vfloat<M> projC0 = dot(c0, ray_dir) * rd2; |
139 | const Vec3vf<M> perp = c0 - projC0 * ray_dir; |
140 | const vfloat<M> l2 = dot(perp, perp); |
141 | const vfloat<M> r2 = radius * radius; |
142 | valid &= (l2 <= r2); |
143 | if (unlikely(none(valid))) |
144 | return false; |
145 | |
146 | const vfloat<M> td = sqrt((r2 - l2) * rd2); |
147 | const vfloat<M> t_front = projC0 - td; |
148 | const vfloat<M> t_back = projC0 + td; |
149 | |
150 | const vbool<M> valid_front = valid & (ray.tnear()[k] <= t_front) & (t_front <= ray.tfar[k]); |
151 | const vbool<M> valid_back = valid & (ray.tnear()[k] <= t_back ) & (t_back <= ray.tfar[k]); |
152 | |
153 | /* check if there is a first hit */ |
154 | const vbool<M> valid_first = valid_front | valid_back; |
155 | if (unlikely(none(valid_first))) |
156 | return false; |
157 | |
158 | /* construct first hit */ |
159 | const vfloat<M> td_front = -td; |
160 | const vfloat<M> td_back = +td; |
161 | const vfloat<M> t_first = select(valid_front, t_front, t_back); |
162 | const Vec3vf<M> Ng_first = select(valid_front, td_front, td_back) * ray_dir - perp; |
163 | SphereIntersectorHitM<M> hit(t_first, Ng_first); |
164 | |
165 | /* invoke intersection filter for first hit */ |
166 | const bool is_hit_first = epilog(valid_first, hit); |
167 | |
168 | /* check for possible second hits before potentially accepted hit */ |
169 | const vfloat<M> t_second = t_back; |
170 | const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar[k]); |
171 | if (unlikely(none(valid_second))) |
172 | return is_hit_first; |
173 | |
174 | /* invoke intersection filter for second hit */ |
175 | const Vec3vf<M> Ng_second = td_back * ray_dir - perp; |
176 | hit = SphereIntersectorHitM<M> (t_second, Ng_second); |
177 | const bool is_hit_second = epilog(valid_second, hit); |
178 | |
179 | return is_hit_first | is_hit_second; |
180 | } |
181 | }; |
182 | } // namespace isa |
183 | } // namespace embree |
184 | |