// Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 #pragma once namespace embree { namespace isa { /*! Intersects a ray with a quad with backface culling * enabled. The quad v0,v1,v2,v3 is split into two triangles * v0,v1,v3 and v2,v3,v1. The edge v1,v2 decides which of the two * triangles gets intersected. */ template __forceinline vbool intersect_quad_backface_culling(const vbool& valid0, const Vec3fa& ray_org, const Vec3fa& ray_dir, const float ray_tnear, const float ray_tfar, const Vec3vf& quad_v0, const Vec3vf& quad_v1, const Vec3vf& quad_v2, const Vec3vf& quad_v3, vfloat& u_o, vfloat& v_o, vfloat& t_o) { /* calculate vertices relative to ray origin */ vbool valid = valid0; const Vec3vf O = Vec3vf(ray_org); const Vec3vf D = Vec3vf(ray_dir); const Vec3vf va = quad_v0-O; const Vec3vf vb = quad_v1-O; const Vec3vf vc = quad_v2-O; const Vec3vf vd = quad_v3-O; const Vec3vf edb = vb-vd; const vfloat WW = dot(cross(vd,edb),D); const Vec3vf v0 = select(WW <= 0.0f,va,vc); const Vec3vf v1 = select(WW <= 0.0f,vb,vd); const Vec3vf v2 = select(WW <= 0.0f,vd,vb); /* calculate edges */ const Vec3vf e0 = v2-v0; const Vec3vf e1 = v0-v1; /* perform edge tests */ const vfloat U = dot(cross(v0,e0),D); const vfloat V = dot(cross(v1,e1),D); valid &= max(U,V) <= 0.0f; if (unlikely(none(valid))) return false; /* calculate geometry normal and denominator */ const Vec3vf Ng = cross(e1,e0); const vfloat den = dot(Ng,D); const vfloat rcpDen = rcp(den); /* perform depth test */ const vfloat t = rcpDen*dot(v0,Ng); valid &= vfloat(ray_tnear) <= t & t <= vfloat(ray_tfar); if (unlikely(none(valid))) return false; /* avoid division by 0 */ valid &= den != vfloat(zero); if (unlikely(none(valid))) return false; /* update hit information */ t_o = t; u_o = U * rcpDen; v_o = V * rcpDen; u_o = select(WW <= 0.0f,u_o,1.0f-u_o); v_o = select(WW <= 0.0f,v_o,1.0f-v_o); return valid; } } }