Path: blob/master/thirdparty/embree/kernels/geometry/roundline_intersector.h
9905 views
// Copyright 2009-2021 Intel Corporation1// SPDX-License-Identifier: Apache-2.023#pragma once45#include "../common/ray.h"6#include "curve_intersector_precalculations.h"789/*1011This file implements the intersection of a ray with a round linear12curve segment. We define the geometry of such a round linear curve13segment from point p0 with radius r0 to point p1 with radius r114using the cone that touches spheres p0/r0 and p1/r1 tangentially15plus the sphere p1/r1. We denote the tangentially touching cone from16p0/r0 to p1/r1 with cone(p0,r0,p1,r1) and the cone plus the ending17sphere with cone_sphere(p0,r0,p1,r1).1819For multiple connected round linear curve segments this construction20yield a proper shape when viewed from the outside. Using the21following CSG we can also handle the interior in most common cases:2223round_linear_curve(pl,rl,p0,r0,p1,r1,pr,rr) =24cone_sphere(p0,r0,p1,r1) - cone(pl,rl,p0,r0) - cone(p1,r1,pr,rr)2526Thus by subtracting the neighboring cone geometries, we cut away27parts of the center cone_sphere surface which lie inside the28combined curve. This approach works as long as geometry of the29current cone_sphere penetrates into direct neighbor segments only,30and not into segments further away.3132To construct a cone that touches two spheres at p0 and p1 with r033and r1, one has to increase the cone radius at r0 and r1 to obtain34larger radii w0 and w1, such that the infinite cone properly touches35the spheres. From the paper "Ray Tracing Generalized Tube36Primitives: Method and Applications"37(https://www.researchgate.net/publication/334378683_Ray_Tracing_Generalized_Tube_Primitives_Method_and_Applications)38one can derive the following equations for these increased39radii:4041sr = 1.0f / sqrt(1-sqr(dr)/sqr(p1-p0))42w0 = sr*r043w1 = sr*r14445Further, we want the cone to start where it touches the sphere at p046and to end where it touches sphere at p1. Therefore, we need to47construct clipping locations y0 and y1 for the start and end of the48cone. These start and end clipping location of the cone can get49calculated as:5051Y0 = - r0 * (r1-r0) / length(p1-p0)52Y1 = length(p1-p0) - r1 * (r1-r0) / length(p1-p0)5354Where the cone starts a distance Y0 and ends a distance Y1 away of55point p0 along the cone center. The distance between Y1-Y0 can get56calculated as:5758dY = length(p1-p0) - (r1-r0)^2 / length(p1-p0)5960In the code below, Y will always be scaled by length(p1-p0) to61obtain y and you will find the terms r0*(r1-r0) and62(p1-p0)^2-(r1-r0)^2.6364*/6566namespace embree67{68namespace isa69{70template<int M>71struct RoundLineIntersectorHitM72{73__forceinline RoundLineIntersectorHitM() {}7475__forceinline RoundLineIntersectorHitM(const vfloat<M>& u, const vfloat<M>& v, const vfloat<M>& t, const Vec3vf<M>& Ng)76: vu(u), vv(v), vt(t), vNg(Ng) {}7778__forceinline void finalize() {}7980__forceinline Vec2f uv (const size_t i) const { return Vec2f(vu[i],vv[i]); }81__forceinline float t (const size_t i) const { return vt[i]; }82__forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i],vNg.y[i],vNg.z[i]); }8384__forceinline Vec2vf<M> uv() const { return Vec2vf<M>(vu,vv); }85__forceinline vfloat<M> t () const { return vt; }86__forceinline Vec3vf<M> Ng() const { return vNg; }8788public:89vfloat<M> vu;90vfloat<M> vv;91vfloat<M> vt;92Vec3vf<M> vNg;93};9495namespace __roundline_internal96{97template<int M>98struct ConeGeometry99{100ConeGeometry (const Vec4vf<M>& a, const Vec4vf<M>& b)101: p0(a.xyz()), p1(b.xyz()), dP(p1-p0), dPdP(dot(dP,dP)), r0(a.w), sqr_r0(sqr(r0)), r1(b.w), dr(r1-r0), drdr(dr*dr), r0dr (r0*dr), g(dPdP - drdr) {}102103/*104105This function tests if a point is accepted by first cone106clipping plane.107108First, we need to project the point onto the line p0->p1:109110Y = (p-p0)*(p1-p0)/length(p1-p0)111112This value y is the distance to the projection point from113p0. The clip distances are calculated as:114115Y0 = - r0 * (r1-r0) / length(p1-p0)116Y1 = length(p1-p0) - r1 * (r1-r0) / length(p1-p0)117118Thus to test if the point p is accepted by the first119clipping plane we need to test Y > Y0 and to test if it120is accepted by the second clipping plane we need to test121Y < Y1.122123By multiplying the calculations with length(p1-p0) these124calculation can get simplied to:125126y = (p-p0)*(p1-p0)127y0 = - r0 * (r1-r0)128y1 = (p1-p0)^2 - r1 * (r1-r0)129130and the test y > y0 and y < y1.131132*/133134__forceinline vbool<M> isClippedByPlane (const vbool<M>& valid_i, const Vec3vf<M>& p) const135{136const Vec3vf<M> p0p = p - p0;137const vfloat<M> y = dot(p0p,dP);138const vfloat<M> cap0 = -r0dr;139const vbool<M> inside_cone = y > cap0;140return valid_i & (p0.x != vfloat<M>(inf)) & (p1.x != vfloat<M>(inf)) & inside_cone;141}142143/*144145This function tests whether a point lies inside the capped cone146tangential to its ending spheres.147148Therefore one has to check if the point is inside the149region defined by the cone clipping planes, which is150performed similar as in the previous function.151152To perform the inside cone test we need to project the153point onto the line p0->p1:154155dP = p1-p0156Y = (p-p0)*dP/length(dP)157158This value Y is the distance to the projection point from159p0. To obtain a parameter value u going from 0 to 1 along160the line p0->p1 we calculate:161162U = Y/length(dP)163164The radii to use at points p0 and p1 are:165166w0 = sr * r0167w1 = sr * r1168dw = w1-w0169170Using these radii and u one can directly test if the point171lies inside the cone using the formula dP*dP < wy*wy with:172173wy = w0 + u*dw174py = p0 + u*dP - p175176By multiplying the calculations with length(p1-p0) and177inserting the definition of w can obtain simpler equations:178179y = (p-p0)*dP180ry = r0 + y/dP^2 * dr181wy = sr*ry182py = p0 + y/dP^2*dP - p183y0 = - r0 * dr184y1 = dP^2 - r1 * dr185186Thus for the in-cone test we get:187188py^2 < wy^2189<=> py^2 < sr^2 * ry^2190<=> py^2 * ( dP^2 - dr^2 ) < dP^2 * ry^2191192This can further get simplified to:193194(p0-p)^2 * (dP^2 - dr^2) - y^2 < dP^2 * r0^2 + 2.0f*r0*dr*y;195196*/197198__forceinline vbool<M> isInsideCappedCone (const vbool<M>& valid_i, const Vec3vf<M>& p) const199{200const Vec3vf<M> p0p = p - p0;201const vfloat<M> y = dot(p0p,dP);202const vfloat<M> cap0 = -r0dr+vfloat<M>(ulp);203const vfloat<M> cap1 = -r1*dr + dPdP;204205vbool<M> inside_cone = valid_i & (p0.x != vfloat<M>(inf)) & (p1.x != vfloat<M>(inf));206inside_cone &= y > cap0; // start clipping plane207inside_cone &= y < cap1; // end clipping plane208inside_cone &= sqr(p0p)*g - sqr(y) < dPdP * sqr_r0 + 2.0f*r0dr*y; // in cone test209return inside_cone;210}211212protected:213Vec3vf<M> p0;214Vec3vf<M> p1;215Vec3vf<M> dP;216vfloat<M> dPdP;217vfloat<M> r0;218vfloat<M> sqr_r0;219vfloat<M> r1;220vfloat<M> dr;221vfloat<M> drdr;222vfloat<M> r0dr;223vfloat<M> g;224};225226template<int M>227struct ConeGeometryIntersector : public ConeGeometry<M>228{229using ConeGeometry<M>::p0;230using ConeGeometry<M>::p1;231using ConeGeometry<M>::dP;232using ConeGeometry<M>::dPdP;233using ConeGeometry<M>::r0;234using ConeGeometry<M>::sqr_r0;235using ConeGeometry<M>::r1;236using ConeGeometry<M>::dr;237using ConeGeometry<M>::r0dr;238using ConeGeometry<M>::g;239240ConeGeometryIntersector (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)241: ConeGeometry<M>(a,b), org(ray_org), O(ray_org-p0), dO(ray_dir), dOdO(dOdO), rcp_dOdO(rcp_dOdO), OdP(dot(dP,O)), dOdP(dot(dP,dO)), yp(OdP + r0dr) {}242243/*244245This function intersects a ray with a cone that touches a246start sphere p0/r0 and end sphere p1/r1.247248To find this ray/cone intersections one could just249calculate radii w0 and w1 as described above and use a250standard ray/cone intersection routine with these251radii. However, it turns out that calculations can get252simplified when deriving a specialized ray/cone253intersection for this special case. We perform254calculations relative to the cone origin p0 and define:255256O = ray_org - p0257dO = ray_dir258dP = p1-p0259dr = r1-r0260dw = w1-w0261262For some t we can compute the potential hit point h = O + t*dO and263project it onto the cone vector dP to obtain u = (h*dP)/(dP*dP). In264case of an intersection, the squared distance from the hit point265projected onto the cone center line to the hit point should be equal266to the squared cone radius at u:267268(u*dP - h)^2 = (w0 + u*dw)^2269270Inserting the definition of h, u, w0, and dw into this formula, then271factoring out all terms, and sorting by t^2, t^1, and t^0 terms272yields a quadratic equation to solve.273274Inserting u:275( (h*dP)*dP/dP^2 - h )^2 = ( w0 + (h*dP)*dw/dP^2 )^2276277Multiplying by dP^4:278( (h*dP)*dP - h*dP^2 )^2 = ( w0*dP^2 + (h*dP)*dw )^2279280Inserting w0 and dw:281( (h*dP)*dP - h*dP^2 )^2 = ( r0*dP^2 + (h*dP)*dr )^2 / (1-dr^2/dP^2)282( (h*dP)*dP - h*dP^2 )^2 *(dP^2 - dr^2) = dP^2 * ( r0*dP^2 + (h*dP)*dr )^2283284Now one can insert the definition of h, factor out, and presort by t:285( ((O + t*dO)*dP)*dP - (O + t*dO)*dP^2 )^2 *(dP^2 - dr^2) = dP^2 * ( r0*dP^2 + ((O + t*dO)*dP)*dr )^2286( (O*dP)*dP-O*dP^2 + t*( (dO*dP)*dP - dO*dP^2 ) )^2 *(dP^2 - dr^2) = dP^2 * ( r0*dP^2 + (O*dP)*dr + t*(dO*dP)*dr )^2287288Factoring out further and sorting by t^2, t^1 and t^0 yields:2892900 = t^2 * [ ((dO*dP)*dP - dO-dP^2)^2 * (dP^2 - dr^2) - dP^2*(dO*dP)^2*dr^2 ]291+ 2*t^1 * [ ((O*dP)*dP - O*dP^2) * ((dO*dP)*dP - dO*dP^2) * (dP^2 - dr^2) - dP^2*(r0*dP^2 + (O*dP)*dr)*(dO*dP)*dr ]292+ t^0 * [ ( (O*dP)*dP - O*dP^2)^2 * (dP^2-dr^2) - dP^2*(r0*dP^2 + (O*dP)*dr)^2 ]293294This can be simplified to:2952960 = t^2 * [ (dP^2 - dr^2)*dO^2 - (dO*dP)^2 ]297+ 2*t^1 * [ (dP^2 - dr^2)*(O*dO) - (dO*dP)*(O*dP + r0*dr) ]298+ t^0 * [ (dP^2 - dr^2)*O^2 - (O*dP)^2 - r0^2*dP^2 - 2.0f*r0*dr*(O*dP) ]299300Solving this quadratic equation yields the values for t at which the301ray intersects the cone.302303*/304305__forceinline bool intersectCone(vbool<M>& valid, vfloat<M>& lower, vfloat<M>& upper)306{307/* return no hit by default */308lower = pos_inf;309upper = neg_inf;310311/* compute quadratic equation A*t^2 + B*t + C = 0 */312const vfloat<M> OO = dot(O,O);313const vfloat<M> OdO = dot(dO,O);314const vfloat<M> A = g * dOdO - sqr(dOdP);315const vfloat<M> B = 2.0f * (g*OdO - dOdP*yp);316const vfloat<M> C = g*OO - sqr(OdP) - sqr_r0*dPdP - 2.0f*r0dr*OdP;317318/* we miss the cone if determinant is smaller than zero */319const vfloat<M> D = B*B - 4.0f*A*C;320valid &= (D >= 0.0f & g > 0.0f); // if g <= 0 then the cone is inside a sphere end321322/* When rays are parallel to the cone surface, then the323* ray may be inside or outside the cone. We just assume a324* miss in that case, which is fine as rays inside the325* cone would anyway hit the ending spheres in that326* case. */327valid &= abs(A) > min_rcp_input;328if (unlikely(none(valid))) {329return false;330}331332/* compute distance to front and back hit */333const vfloat<M> Q = sqrt(D);334const vfloat<M> rcp_2A = rcp(2.0f*A);335t_cone_front = (-B-Q)*rcp_2A;336y_cone_front = yp + t_cone_front*dOdP;337lower = select( (y_cone_front > -(float)ulp) & (y_cone_front <= g) & (g > 0.0f), t_cone_front, vfloat<M>(pos_inf));338#if !defined (EMBREE_BACKFACE_CULLING_CURVES)339t_cone_back = (-B+Q)*rcp_2A;340y_cone_back = yp + t_cone_back *dOdP;341upper = select( (y_cone_back > -(float)ulp) & (y_cone_back <= g) & (g > 0.0f), t_cone_back , vfloat<M>(neg_inf));342#endif343return true;344}345346/*347This function intersects the ray with the end sphere at348p1. We already clip away hits that are inside the349neighboring cone segment.350351*/352353__forceinline void intersectEndSphere(vbool<M>& valid,354const ConeGeometry<M>& coneR,355vfloat<M>& lower, vfloat<M>& upper)356{357/* calculate front and back hit with end sphere */358const Vec3vf<M> O1 = org - p1;359const vfloat<M> O1dO = dot(O1,dO);360const vfloat<M> h2 = sqr(O1dO) - dOdO*(sqr(O1) - sqr(r1));361const vfloat<M> rhs1 = select( h2 >= 0.0f, sqrt(h2), vfloat<M>(neg_inf) );362363/* clip away front hit if it is inside next cone segment */364t_sph1_front = (-O1dO - rhs1)*rcp_dOdO;365const Vec3vf<M> hit_front = org + t_sph1_front*dO;366vbool<M> valid_sph1_front = h2 >= 0.0f & yp + t_sph1_front*dOdP > g & !coneR.isClippedByPlane (valid, hit_front);367lower = select(valid_sph1_front, t_sph1_front, vfloat<M>(pos_inf));368369#if !defined(EMBREE_BACKFACE_CULLING_CURVES)370/* clip away back hit if it is inside next cone segment */371t_sph1_back = (-O1dO + rhs1)*rcp_dOdO;372const Vec3vf<M> hit_back = org + t_sph1_back*dO;373vbool<M> valid_sph1_back = h2 >= 0.0f & yp + t_sph1_back*dOdP > g & !coneR.isClippedByPlane (valid, hit_back);374upper = select(valid_sph1_back, t_sph1_back, vfloat<M>(neg_inf));375#else376upper = vfloat<M>(neg_inf);377#endif378}379380__forceinline void intersectBeginSphere(const vbool<M>& valid,381vfloat<M>& lower, vfloat<M>& upper)382{383/* calculate front and back hit with end sphere */384const Vec3vf<M> O1 = org - p0;385const vfloat<M> O1dO = dot(O1,dO);386const vfloat<M> h2 = sqr(O1dO) - dOdO*(sqr(O1) - sqr(r0));387const vfloat<M> rhs1 = select( h2 >= 0.0f, sqrt(h2), vfloat<M>(neg_inf) );388389/* clip away front hit if it is inside next cone segment */390t_sph0_front = (-O1dO - rhs1)*rcp_dOdO;391vbool<M> valid_sph1_front = valid & h2 >= 0.0f & yp + t_sph0_front*dOdP < 0;392lower = select(valid_sph1_front, t_sph0_front, vfloat<M>(pos_inf));393394#if !defined(EMBREE_BACKFACE_CULLING_CURVES)395/* clip away back hit if it is inside next cone segment */396t_sph0_back = (-O1dO + rhs1)*rcp_dOdO;397vbool<M> valid_sph1_back = valid & h2 >= 0.0f & yp + t_sph0_back*dOdP < 0;398upper = select(valid_sph1_back, t_sph0_back, vfloat<M>(neg_inf));399#else400upper = vfloat<M>(neg_inf);401#endif402}403404/*405406This function calculates the geometry normal of some cone hit.407408For a given hit point h (relative to p0) with a cone409starting at p0 with radius w0 and ending at p1 with410radius w1 one normally calculates the geometry normal by411first calculating the parmetric u hit location along the412cone:413414u = dot(h,dP)/dP^2415416Using this value one can now directly calculate the417geometry normal by bending the connection vector (h-u*dP)418from hit to projected hit with some cone dependent value419dw/sqrt(dP^2) * normalize(dP):420421Ng = normalize(h-u*dP) - dw/length(dP) * normalize(dP)422423The length of the vector (h-u*dP) can also get calculated424by interpolating the radii as w0+u*dw which yields:425426Ng = (h-u*dP)/(w0+u*dw) - dw/dP^2 * dP427428Multiplying with (w0+u*dw) yield a scaled Ng':429430Ng' = (h-u*dP) - (w0+u*dw)*dw/dP^2*dP431432Inserting the definition of w0 and dw and refactoring433yield a further scaled Ng'':434435Ng'' = (dP^2 - dr^2) (h-q) - (r0+u*dr)*dr*dP436437Now inserting the definition of u gives and multiplying438with the denominator yields:439440Ng''' = (dP^2-dr^2)*(dP^2*h-dot(h,dP)*dP) - (dP^2*r0+dot(h,dP)*dr)*dr*dP441442Factoring out, cancelling terms, dividing by dP^2, and443factoring again yields finally:444445Ng'''' = (dP^2-dr^2)*h - dP*(dot(h,dP) + r0*dr)446447*/448449__forceinline Vec3vf<M> Ng_cone(const vbool<M>& front_hit) const450{451#if !defined(EMBREE_BACKFACE_CULLING_CURVES)452const vfloat<M> y = select(front_hit, y_cone_front, y_cone_back);453const vfloat<M> t = select(front_hit, t_cone_front, t_cone_back);454const Vec3vf<M> h = O + t*dO;455return g*h-dP*y;456#else457const Vec3vf<M> h = O + t_cone_front*dO;458return g*h-dP*y_cone_front;459#endif460}461462/* compute geometry normal of sphere hit as the difference463* vector from hit point to sphere center */464465__forceinline Vec3vf<M> Ng_sphere1(const vbool<M>& front_hit) const466{467#if !defined(EMBREE_BACKFACE_CULLING_CURVES)468const vfloat<M> t_sph1 = select(front_hit, t_sph1_front, t_sph1_back);469return org+t_sph1*dO-p1;470#else471return org+t_sph1_front*dO-p1;472#endif473}474475__forceinline Vec3vf<M> Ng_sphere0(const vbool<M>& front_hit) const476{477#if !defined(EMBREE_BACKFACE_CULLING_CURVES)478const vfloat<M> t_sph0 = select(front_hit, t_sph0_front, t_sph0_back);479return org+t_sph0*dO-p0;480#else481return org+t_sph0_front*dO-p0;482#endif483}484485/*486This function calculates the u coordinate of a487hit. Therefore we use the hit distance y (which is zero488at the first cone clipping plane) and divide by distance489g between the clipping planes.490491*/492493__forceinline vfloat<M> u_cone(const vbool<M>& front_hit) const494{495#if !defined(EMBREE_BACKFACE_CULLING_CURVES)496const vfloat<M> y = select(front_hit, y_cone_front, y_cone_back);497return clamp(y*rcp(g));498#else499return clamp(y_cone_front*rcp(g));500#endif501}502503private:504Vec3vf<M> org;505Vec3vf<M> O;506Vec3vf<M> dO;507vfloat<M> dOdO;508vfloat<M> rcp_dOdO;509vfloat<M> OdP;510vfloat<M> dOdP;511512/* for ray/cone intersection */513private:514vfloat<M> yp;515vfloat<M> y_cone_front;516vfloat<M> t_cone_front;517#if !defined (EMBREE_BACKFACE_CULLING_CURVES)518vfloat<M> y_cone_back;519vfloat<M> t_cone_back;520#endif521522/* for ray/sphere intersection */523private:524vfloat<M> t_sph1_front;525vfloat<M> t_sph0_front;526#if !defined (EMBREE_BACKFACE_CULLING_CURVES)527vfloat<M> t_sph1_back;528vfloat<M> t_sph0_back;529#endif530};531532533template<int M, typename Epilog, typename ray_tfar_func>534static __forceinline bool intersectConeSphere(const vbool<M>& valid_i,535const Vec3vf<M>& ray_org_in, const Vec3vf<M>& ray_dir,536const vfloat<M>& ray_tnear, const ray_tfar_func& ray_tfar,537const Vec4vf<M>& v0, const Vec4vf<M>& v1,538const Vec4vf<M>& vL, const Vec4vf<M>& vR,539const Epilog& epilog)540{541vbool<M> valid = valid_i;542543/* move ray origin closer to make calculations numerically stable */544const vfloat<M> dOdO = sqr(ray_dir);545const vfloat<M> rcp_dOdO = rcp(dOdO);546const Vec3vf<M> center = vfloat<M>(0.5f)*(v0.xyz()+v1.xyz());547const vfloat<M> dt = dot(center-ray_org_in,ray_dir)*rcp_dOdO;548const Vec3vf<M> ray_org = ray_org_in + dt*ray_dir;549550/* intersect with cone from v0 to v1 */551vfloat<M> t_cone_lower, t_cone_upper;552ConeGeometryIntersector<M> cone (ray_org, ray_dir, dOdO, rcp_dOdO, v0, v1);553vbool<M> validCone = valid;554cone.intersectCone(validCone, t_cone_lower, t_cone_upper);555556valid &= (validCone | (cone.g <= 0.0f)); // if cone is entirely in sphere end - check sphere557if (unlikely(none(valid)))558return false;559560/* cone hits inside the neighboring capped cones are inside the geometry and thus ignored */561const ConeGeometry<M> coneL (v0, vL);562const ConeGeometry<M> coneR (v1, vR);563#if !defined(EMBREE_BACKFACE_CULLING_CURVES)564const Vec3vf<M> hit_lower = ray_org + t_cone_lower*ray_dir;565const Vec3vf<M> hit_upper = ray_org + t_cone_upper*ray_dir;566t_cone_lower = select (!coneL.isInsideCappedCone (validCone, hit_lower) & !coneR.isInsideCappedCone (validCone, hit_lower), t_cone_lower, vfloat<M>(pos_inf));567t_cone_upper = select (!coneL.isInsideCappedCone (validCone, hit_upper) & !coneR.isInsideCappedCone (validCone, hit_upper), t_cone_upper, vfloat<M>(neg_inf));568#endif569570/* intersect ending sphere */571vfloat<M> t_sph1_lower, t_sph1_upper;572vfloat<M> t_sph0_lower = vfloat<M>(pos_inf);573vfloat<M> t_sph0_upper = vfloat<M>(neg_inf);574cone.intersectEndSphere(valid, coneR, t_sph1_lower, t_sph1_upper);575576const vbool<M> isBeginPoint = valid & (vL[0] == vfloat<M>(pos_inf));577if (unlikely(any(isBeginPoint))) {578cone.intersectBeginSphere (isBeginPoint, t_sph0_lower, t_sph0_upper);579}580581/* CSG union of cone and end sphere */582vfloat<M> t_sph_lower = min(t_sph0_lower, t_sph1_lower);583vfloat<M> t_cone_sphere_lower = min(t_cone_lower, t_sph_lower);584#if !defined (EMBREE_BACKFACE_CULLING_CURVES)585vfloat<M> t_sph_upper = max(t_sph0_upper, t_sph1_upper);586vfloat<M> t_cone_sphere_upper = max(t_cone_upper, t_sph_upper);587588/* filter out hits that are not in tnear/tfar range */589const vbool<M> valid_lower = valid & ray_tnear <= dt+t_cone_sphere_lower & dt+t_cone_sphere_lower <= ray_tfar() & t_cone_sphere_lower != vfloat<M>(pos_inf);590const vbool<M> valid_upper = valid & ray_tnear <= dt+t_cone_sphere_upper & dt+t_cone_sphere_upper <= ray_tfar() & t_cone_sphere_upper != vfloat<M>(neg_inf);591592/* check if there is a first hit */593const vbool<M> valid_first = valid_lower | valid_upper;594if (unlikely(none(valid_first)))595return false;596597/* construct first hit */598const vfloat<M> t_first = select(valid_lower, t_cone_sphere_lower, t_cone_sphere_upper);599const vbool<M> cone_hit_first = t_first == t_cone_lower | t_first == t_cone_upper;600const vbool<M> sph0_hit_first = t_first == t_sph0_lower | t_first == t_sph0_upper;601const Vec3vf<M> Ng_first = select(cone_hit_first, cone.Ng_cone(valid_lower), select (sph0_hit_first, cone.Ng_sphere0(valid_lower), cone.Ng_sphere1(valid_lower)));602const vfloat<M> u_first = select(cone_hit_first, cone.u_cone(valid_lower), select (sph0_hit_first, vfloat<M>(zero), vfloat<M>(one)));603604/* invoke intersection filter for first hit */605RoundLineIntersectorHitM<M> hit(u_first,zero,dt+t_first,Ng_first);606const bool is_hit_first = epilog(valid_first, hit);607608/* check for possible second hits before potentially accepted hit */609const vfloat<M> t_second = t_cone_sphere_upper;610const vbool<M> valid_second = valid_lower & valid_upper & (dt+t_cone_sphere_upper <= ray_tfar());611if (unlikely(none(valid_second)))612return is_hit_first;613614/* invoke intersection filter for second hit */615const vbool<M> cone_hit_second = t_second == t_cone_lower | t_second == t_cone_upper;616const vbool<M> sph0_hit_second = t_second == t_sph0_lower | t_second == t_sph0_upper;617const Vec3vf<M> Ng_second = select(cone_hit_second, cone.Ng_cone(false), select (sph0_hit_second, cone.Ng_sphere0(false), cone.Ng_sphere1(false)));618const vfloat<M> u_second = select(cone_hit_second, cone.u_cone(false), select (sph0_hit_second, vfloat<M>(zero), vfloat<M>(one)));619620hit = RoundLineIntersectorHitM<M>(u_second,zero,dt+t_second,Ng_second);621const bool is_hit_second = epilog(valid_second, hit);622623return is_hit_first | is_hit_second;624#else625/* filter out hits that are not in tnear/tfar range */626const vbool<M> valid_lower = valid & ray_tnear <= dt+t_cone_sphere_lower & dt+t_cone_sphere_lower <= ray_tfar() & t_cone_sphere_lower != vfloat<M>(pos_inf);627628/* check if there is a valid hit */629if (unlikely(none(valid_lower)))630return false;631632/* construct first hit */633const vbool<M> cone_hit_first = t_cone_sphere_lower == t_cone_lower | t_cone_sphere_lower == t_cone_upper;634const vbool<M> sph0_hit_first = t_cone_sphere_lower == t_sph0_lower | t_cone_sphere_lower == t_sph0_upper;635const Vec3vf<M> Ng_first = select(cone_hit_first, cone.Ng_cone(valid_lower), select (sph0_hit_first, cone.Ng_sphere0(valid_lower), cone.Ng_sphere1(valid_lower)));636const vfloat<M> u_first = select(cone_hit_first, cone.u_cone(valid_lower), select (sph0_hit_first, vfloat<M>(zero), vfloat<M>(one)));637638/* invoke intersection filter for first hit */639RoundLineIntersectorHitM<M> hit(u_first,zero,dt+t_cone_sphere_lower,Ng_first);640const bool is_hit_first = epilog(valid_lower, hit);641642return is_hit_first;643#endif644}645646} // end namespace __roundline_internal647648template<int M>649struct RoundLinearCurveIntersector1650{651typedef CurvePrecalculations1 Precalculations;652653template<typename Ray>654struct ray_tfar {655Ray& ray;656__forceinline ray_tfar(Ray& ray) : ray(ray) {}657__forceinline vfloat<M> operator() () const { return ray.tfar; };658};659660template<typename Ray, typename Epilog>661static __forceinline bool intersect(const vbool<M>& valid_i,662Ray& ray,663RayQueryContext* context,664const LineSegments* geom,665const Precalculations& pre,666const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,667const Vec4vf<M>& vLi, const Vec4vf<M>& vRi,668const Epilog& epilog)669{670const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z);671const Vec3vf<M> ray_dir(ray.dir.x, ray.dir.y, ray.dir.z);672const vfloat<M> ray_tnear(ray.tnear());673const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);674const Vec4vf<M> v1 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v1i);675const Vec4vf<M> vL = enlargeRadiusToMinWidth<M>(context,geom,ray_org,vLi);676const Vec4vf<M> vR = enlargeRadiusToMinWidth<M>(context,geom,ray_org,vRi);677return __roundline_internal::intersectConeSphere<M>(valid_i,ray_org,ray_dir,ray_tnear,ray_tfar<Ray>(ray),v0,v1,vL,vR,epilog);678}679};680681template<int M, int K>682struct RoundLinearCurveIntersectorK683{684typedef CurvePrecalculationsK<K> Precalculations;685686struct ray_tfar {687RayK<K>& ray;688size_t k;689__forceinline ray_tfar(RayK<K>& ray, size_t k) : ray(ray), k(k) {}690__forceinline vfloat<M> operator() () const { return ray.tfar[k]; };691};692693template<typename Epilog>694static __forceinline bool intersect(const vbool<M>& valid_i,695RayK<K>& ray, size_t k,696RayQueryContext* context,697const LineSegments* geom,698const Precalculations& pre,699const Vec4vf<M>& v0i, const Vec4vf<M>& v1i,700const Vec4vf<M>& vLi, const Vec4vf<M>& vRi,701const Epilog& epilog)702{703const Vec3vf<M> ray_org(ray.org.x[k], ray.org.y[k], ray.org.z[k]);704const Vec3vf<M> ray_dir(ray.dir.x[k], ray.dir.y[k], ray.dir.z[k]);705const vfloat<M> ray_tnear = ray.tnear()[k];706const Vec4vf<M> v0 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v0i);707const Vec4vf<M> v1 = enlargeRadiusToMinWidth<M>(context,geom,ray_org,v1i);708const Vec4vf<M> vL = enlargeRadiusToMinWidth<M>(context,geom,ray_org,vLi);709const Vec4vf<M> vR = enlargeRadiusToMinWidth<M>(context,geom,ray_org,vRi);710return __roundline_internal::intersectConeSphere<M>(valid_i,ray_org,ray_dir,ray_tnear,ray_tfar(ray,k),v0,v1,vL,vR,epilog);711}712};713}714}715716717