Skip to content

Commit c5133cf

Browse files
committed
in ray space (more precise)
1 parent 71fca72 commit c5133cf

2 files changed

Lines changed: 61 additions & 44 deletions

File tree

common/math/linearspace3.h

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,18 @@ namespace embree
113113
template<typename T> __forceinline LinearSpace3<T> operator +( const LinearSpace3<T>& a ) { return LinearSpace3<T>(+a.vx,+a.vy,+a.vz); }
114114
template<typename T> __forceinline LinearSpace3<T> rcp ( const LinearSpace3<T>& a ) { return a.inverse(); }
115115

116-
/* constructs a coordinate frame form a normalized normal */
116+
/* constructs a coordinate frame form a normalized normal
117+
following http://jcgt.org/published/0006/01/01/ */
117118
template<typename T> __forceinline LinearSpace3<T> frame(const T& N)
118119
{
119-
const T dx0(0,N.z,-N.y);
120-
const T dx1(-N.z,0,N.x);
121-
const T dx = normalize(select(dot(dx0,dx0) > dot(dx1,dx1),dx0,dx1));
122-
const T dy = normalize(cross(N,dx));
120+
const typename T::Scalar sgn = sign(N.z);
121+
const typename T::Scalar rs = N.z - sgn;
122+
const typename T::Scalar a = rcp(rs);
123+
const typename T::Scalar rxxs = N.x*N.x + sgn*rs;
124+
const typename T::Scalar ryys = N.y*N.y + sgn*rs;
125+
const typename T::Scalar rxy = N.x*N.y;
126+
const T dx = T(rxxs*a,rxy*a,N.x);
127+
const T dy = T(rxy*a,ryys*a,N.y);
123128
return LinearSpace3<T>(dx,dy,N);
124129
}
125130

kernels/geometry/roundline_intersector.h

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,10 @@ namespace embree
161161
(p0-p)^2 * (dP^2 - dr^2) - y^2 < dP^2 * r0^2 + 2.0f*r0*dr*y;
162162
*/
163163

164-
__forceinline vbool<M> isInsideCappedCone(const vbool<M>& valid_i, const Vec3vf<M>& p) const
164+
__forceinline vbool<M> isInsideCappedCone(const vbool<M>& valid_i, const vfloat<M>& t) const
165165
{
166-
const Vec3vf<M> p0p = p - p0;
166+
Vec3vf<M> p0p = -p0;
167+
p0p.z += t;
167168
const vfloat<M> y = dot(p0p,dP);
168169
const vfloat<M> cap0 = vfloat<M>(ulp) - r0dr;
169170
const vfloat<M> cap1 = dPdP - r1*dr;
@@ -193,22 +194,20 @@ namespace embree
193194
struct ConeGeometryIntersector : public ConeGeometry<M>
194195
{
195196
using ConeGeometry<M>::p0;
196-
using ConeGeometry<M>::p1;
197197
using ConeGeometry<M>::dP;
198-
using ConeGeometry<M>::dPdP;
199198
using ConeGeometry<M>::r0;
200199
using ConeGeometry<M>::sqr_r0;
201-
using ConeGeometry<M>::r1;
202200
using ConeGeometry<M>::dr;
203201
using ConeGeometry<M>::r0dr;
202+
using ConeGeometry<M>::drdr;
204203
using ConeGeometry<M>::g;
205204

206-
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)
207-
: ConeGeometry<M>(a,b), org(ray_org), P(p0-ray_org), dO(ray_dir), dOdO(dOdO), rcp_dOdO(rcp_dOdO), OdO(dot(dO,P)), dOdP(dot(dP,dO)), OdO_dOdO(OdO*rcp_dOdO), dOdP_dOdO(dOdP*rcp_dOdO) {
208-
const Vec3vf<M> l = P - OdO_dOdO * dO; // more precise than dot(P,P) - OdO^2/dOdO (catastrophic cancellation of squared terms)
209-
G = sqr_r0 - sqr(l);
210-
C = g - dOdP * dOdP_dOdO;
211-
F = r0dr - dot(dP,P) + dOdP * OdO_dOdO;
205+
ConeGeometryIntersector(const Vec4vf<M>& a, const Vec4vf<M>& b)
206+
: ConeGeometry<M>(a,b) {
207+
G = sqr_r0 - sqr(p0.x) - sqr(p0.y);
208+
C = sqr(dP.x) + sqr(dP.y) - drdr;
209+
E = sqr(dP.z) + C;
210+
F = r0dr - p0.x*dP.x - p0.y*dP.y;
212211
}
213212

214213
/*
@@ -220,21 +219,21 @@ namespace embree
220219
__forceinline bool intersectConeU(vbool<M>& valid, vfloat<M>& u_front, vfloat<M>& u_back)
221220
{
222221
/* we miss the cone if determinant is smaller than zero */
223-
const vfloat<M> D = (F*F + G*C) * rcp_dOdO * rcp(g);
222+
const vfloat<M> D = (F*F + G*C) * rcp(E);
224223
valid &= (D >= 0.0f) | (g <= 0.0f); // or inside a sphere end
225224

226225
if (unlikely(none(valid)))
227226
return false;
228227

229-
const vfloat<M> Q = dOdP * sqrt(D);
228+
const vfloat<M> Q = dP.z * sqrt(D);
230229
const vfloat<M> rcp_C = rcp(C);
231230
vfloat<M> u0 = (F + Q) * rcp_C;
232231
vfloat<M> u1 = (F - Q) * rcp_C;
233232
// flip negative caps to other side
234233
u0 = select(r0 + u0*dr < 0.0f, 1.0f-u0, u0);
235234
u1 = select(r0 + u1*dr < 0.0f, 1.0f-u1, u1);
236235
const vfloat<M> uend = select(dr >= 0.0f, vfloat<M>(one), vfloat<M>(zero));
237-
const vbool<M> swap = (dOdP >= 0.0) != (u1 > u0);
236+
const vbool<M> swap = (dP.z >= 0.0) != (u1 > u0);
238237
// already clamp for end sphere (always present)
239238
u_front = min(1.0f, select(g > 0.0f, select(swap, u1, u0), uend));
240239
#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
@@ -265,67 +264,77 @@ namespace embree
265264
This normal is valid for the cone as well for the end cap spheres.
266265
267266
Ng = h - (p0 + u*dP)
267+
h = (0,0,t)
268268
*/
269269

270270
__forceinline Vec3vf<M> Ng(const vfloat<M>& u, const vfloat<M>& t) const
271271
{
272-
return t*dO-P - u*dP;
272+
Vec3vf<M> n = -(p0 + u*dP);
273+
n.z += t;
274+
return n;
273275
}
274276

275277
private:
276-
Vec3vf<M> org;
277-
Vec3vf<M> P;
278-
Vec3vf<M> dO;
279-
vfloat<M> dOdO;
280-
vfloat<M> rcp_dOdO;
281-
vfloat<M> OdO;
282-
vfloat<M> dOdP;
283-
vfloat<M> OdO_dOdO;
284-
vfloat<M> dOdP_dOdO;
285278
vfloat<M> C;
279+
vfloat<M> E;
286280
vfloat<M> F;
287281
vfloat<M> G;
288282
};
289283

290284
template<int M, typename Epilog, typename ray_tfar_func>
291285
static __forceinline bool intersectConeSphere(const vbool<M>& valid_i,
292-
const Vec3vf<M>& ray_org, const Vec3vf<M>& ray_dir,
286+
const Vec3vf<M>& ray_org, const Vec3vf<M>& ray_dir_in,
293287
const vfloat<M>& ray_tnear, const ray_tfar_func& ray_tfar,
294-
const Vec4vf<M>& v0, const Vec4vf<M>& v1,
295-
const Vec4vf<M>& vL, const Vec4vf<M>& vR,
288+
const Vec4vf<M>& v0_in, const Vec4vf<M>& v1_in,
289+
const Vec4vf<M>& vL_in, const Vec4vf<M>& vR_in,
296290
const Epilog& epilog)
297291
{
298292
vbool<M> valid = valid_i;
299293

300-
const vfloat<M> dOdO = sqr(ray_dir);
301-
const vfloat<M> rcp_dOdO = rcp(dOdO);
294+
// normalize ray dir, keep length
295+
const vfloat<M> rcp_rd = rcp_length(ray_dir_in);
296+
const vfloat<M> rd = rcp(rcp_rd);
297+
const Vec3vf<M>& ray_dir = ray_dir_in*rcp_rd;
298+
299+
// transform into ray space
300+
const LinearSpace3vf<M> m = frame(ray_dir);
301+
const Vec4vf<M> v0 = Vec4vf<M>(m*(Vec3vf<M>(v0_in)-ray_org), v0_in.w);
302+
const Vec4vf<M> v1 = Vec4vf<M>(m*(Vec3vf<M>(v1_in)-ray_org), v1_in.w);
302303

303304
/* intersect with cone from v0 to v1 */
304-
ConeGeometryIntersector<M> cone (ray_org, ray_dir, dOdO, rcp_dOdO, v0, v1);
305+
ConeGeometryIntersector<M> cone(v0, v1);
305306
vfloat<M> u_front, u_back;
306307
if (unlikely(!cone.intersectConeU(valid, u_front, u_back)))
307308
return false;
308309

309310
/* calculate front hit */
310-
vbool<M> validFront = valid & ((u_front >= 0.0f) | (vL[0] == vfloat<M>(pos_inf)));
311+
vbool<M> validFront = valid & ((u_front >= 0.0f) | (vL_in[0] == vfloat<M>(pos_inf)));
311312
u_front = max(u_front, 0.0f);
312313
vfloat<M> t_lower;
313314
cone.template intersectSphere<true>(validFront, u_front, t_lower);
314315

316+
// for normal
317+
Vec3vf<M> dP = v0_in.xyz() - v1_in.xyz();
318+
Vec3vf<M> P = ray_org - v0_in.xyz();
319+
315320
#if !defined (EMBREE_BACKFACE_CULLING_CURVES)
316321
/* hits inside the neighboring capped cones are inside the geometry and thus ignored */
322+
const Vec4vf<M> vL = Vec4vf<M>(m*(Vec3vf<M>(vL_in)-ray_org), vL_in.w);
317323
const ConeGeometry<M> coneL (v0, vL);
324+
const Vec4vf<M> vR = Vec4vf<M>(m*(Vec3vf<M>(vR_in)-ray_org), vR_in.w);
318325
const ConeGeometry<M> coneR (v1, vR);
319-
const Vec3vf<M> hit_lower = ray_org + t_lower*ray_dir;
320-
validFront &= !coneL.isInsideCappedCone(validFront, hit_lower) & !coneR.isInsideCappedCone(validFront, hit_lower);
326+
validFront &= !coneL.isInsideCappedCone(validFront, t_lower) & !coneR.isInsideCappedCone(validFront, t_lower);
321327

322328
/* calculate back hit */
323-
vbool<M> validBack = valid & ((u_back >= 0.0f) | (vL[0] == vfloat<M>(pos_inf)));
329+
vbool<M> validBack = valid & ((u_back >= 0.0f) | (vL_in[0] == vfloat<M>(pos_inf)));
324330
u_back = max(u_back, 0.0f);
325331
vfloat<M> t_upper;
326332
cone.template intersectSphere<false>(validBack, u_back, t_upper);
327-
const Vec3vf<M> hit_upper = ray_org + t_upper*ray_dir;
328-
validBack &= !coneL.isInsideCappedCone(validBack, hit_upper) & !coneR.isInsideCappedCone(validBack, hit_upper);
333+
validBack &= !coneL.isInsideCappedCone(validBack, t_upper) & !coneR.isInsideCappedCone(validBack, t_upper);
334+
335+
// scale back
336+
t_lower *= rd;
337+
t_upper *= rd;
329338

330339
/* filter out hits that are not in tnear/tfar range */
331340
const vbool<M> valid_lower = validFront & ray_tnear <= t_lower & t_lower <= ray_tfar();
@@ -341,7 +350,7 @@ namespace embree
341350
const vfloat<M> u_first = select(valid_lower, u_front, u_back);
342351

343352
/* invoke intersection filter for first hit */
344-
RoundLineIntersectorHitM<M> hit(u_first,zero,t_first,cone.Ng(u_first,t_first));
353+
RoundLineIntersectorHitM<M> hit(u_first,zero,t_first,t_first*ray_dir_in + P + u_first*dP);
345354
const bool is_hit_first = epilog(valid_first, hit);
346355

347356
/* check for possible second hits before potentially accepted hit */
@@ -350,11 +359,14 @@ namespace embree
350359
return is_hit_first;
351360

352361
/* invoke intersection filter for second hit */
353-
hit = RoundLineIntersectorHitM<M>(u_back,zero,t_upper,cone.Ng(u_back,t_upper));
362+
hit = RoundLineIntersectorHitM<M>(u_back,zero,t_upper,t_upper*ray_dir_in + P + u_back*dP);
354363
const bool is_hit_second = epilog(valid_second, hit);
355364

356365
return is_hit_first | is_hit_second;
357366
#else
367+
// scale back
368+
t_lower *= rd;
369+
358370
/* filter out hits that are not in tnear/tfar range */
359371
const vbool<M> valid_lower = validFront & ray_tnear <= t_lower & t_lower <= ray_tfar();
360372

@@ -363,7 +375,7 @@ namespace embree
363375
return false;
364376

365377
/* construct first hit and invoke intersection filter for first hit */
366-
RoundLineIntersectorHitM<M> hit(u_front,zero,t_lower,cone.Ng(u_front,t_lower));
378+
RoundLineIntersectorHitM<M> hit(u_front,zero,t_lower,t_lower*ray_dir_in + P + u_front*dP);
367379
const bool is_hit_first = epilog(valid_lower, hit);
368380

369381
return is_hit_first;

0 commit comments

Comments
 (0)