Intel® Embree Ray Tracing Kernels
Discussion forum on the open source ray tracing kernels for fast photo-realistic rendering on Intel® CPU(s)

intersection test with increased tolerance

Lee__Heungson
Beginner
1,163 Views

I am trying to test collision detection by using embree. For this configuration I need more flexible intersection test (meaning larger epsilon) for triangle meshes.  

 

For example, if I consider a triangle with following vertices (v0, v1, v2)

v0.x = 0.; v0.y = 0.; v0.z = 0.;

v1.x = 0.; v1.y = 100.; v1.z = 0.;

v2.x = 100.; v2.y = 100.; v2.z = 100.;

and the ray with

org.x = -eps; org.y = 0.; org.z = -10.;

dir.x = 0.; dir.y = 0.; dir.z = 1.;

where (eps > default eps)

The ray won't intersect the triangle.

 

And I found this article and applied what this comment suggested

https://software.intel.com/en-us/forums/embree-photo-realistic-ray-tracing-kernels/topic/755654#comment-1918389

 

For some test cases it worked fine

but for the other cases it didn't work because 

it was not able to pass node intersection test before actually going into triangle intersection test.

For a single ray test, I guess it has something to do with this part of the code in  node_intersector1.h 

 

template<int N, int Nx>
      __forceinline size_t intersectNodeRobust(const typename BVHN<N>::AlignedNode* node, const TravRay<N,Nx,true>& ray, vfloat<Nx>& dist)
    {      
      const vfloat<N> tNearX = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.nearX)) - ray.org.x) * ray.rdir_near.x;
      const vfloat<N> tNearY = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.nearY)) - ray.org.y) * ray.rdir_near.y;
      const vfloat<N> tNearZ = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.nearZ)) - ray.org.z) * ray.rdir_near.z;
      const vfloat<N> tFarX  = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.farX )) - ray.org.x) * ray.rdir_far.x;
      const vfloat<N> tFarY  = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.farY )) - ray.org.y) * ray.rdir_far.y;
      const vfloat<N> tFarZ  = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.farZ )) - ray.org.z) * ray.rdir_far.z;
      const vfloat<N> tNear = max(tNearX,tNearY,tNearZ,ray.tnear);
      const vfloat<N> tFar  = min(tFarX ,tFarY ,tFarZ ,ray.tfar);
      const vbool<N> vmask = tNear <= tFar;
      const size_t mask = movemask(vmask);
      dist = tNear;
      return mask;
    }

The problem is that I have no idea what this code means.

 

My question is

1. Can I modify the way intersection test works with bounding volumes?

2. if 1 is not possible, can I modify the way bounding volumes are created? 

If the above are not good idea, I'll try user geometry. 

 

Please help me.

0 Kudos
3 Replies
Lee__Heungson
Beginner
1,163 Views

I am self-answering my question. I modified the above intersection test with

 

      const vfloat4 eps_x = float(ulp) * (vfloat4::load((float*)((const char*)&node->lower_x + ray.farX)) - vfloat4::load((float*)((const char*)&node->lower_x + ray.nearX)));
      const vfloat4 eps_y = float(ulp) * (vfloat4::load((float*)((const char*)&node->lower_x + ray.farY)) - vfloat4::load((float*)((const char*)&node->lower_x + ray.nearY)));
      const vfloat4 eps_z = float(ulp) * (vfloat4::load((float*)((const char*)&node->lower_x + ray.farZ)) - vfloat4::load((float*)((const char*)&node->lower_x + ray.nearZ)));

      const vfloat<N> tNearX = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.nearX)) - eps_x - ray.org.x) * ray.rdir_near.x;
      const vfloat<N> tNearY = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.nearY)) - eps_y - ray.org.y) * ray.rdir_near.y;
      const vfloat<N> tNearZ = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.nearZ)) - eps_z - ray.org.z) * ray.rdir_near.z;
      const vfloat<N> tFarX  = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.farX )) + eps_x - ray.org.x) * ray.rdir_far.x;
      const vfloat<N> tFarY  = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.farY )) + eps_y - ray.org.y) * ray.rdir_far.y;
      const vfloat<N> tFarZ  = (vfloat<N>::load((float*)((const char*)&node->lower_x+ray.farZ )) + eps_z - ray.org.z) * ray.rdir_far.z;
      

with the following change in contants.h
 

struct UlpTy
  {
    __forceinline operator double( ) const { return std::numeric_limits<double>::epsilon(); }
    __forceinline operator float ( ) const { return float(1.e-3); }
  };

I am testing this even though I am not sure what kind of side effects these change will cause.

0 Kudos
BenthinC_Intel
Employee
1,163 Views

If you really need larger epsilons during BVH traversal it might be easier to adjust the final tNear, tFar values instead of each dimension individually. However, BVH traversal in robust mode is already conservative in the node intersection test, so I'm just wondering why you need even larger epsilons?

0 Kudos
Lee__Heungson
Beginner
1,163 Views

Carsten Benthin (Intel) wrote:

If you really need larger epsilons during BVH traversal it might be easier to adjust the final tNear, tFar values instead of each dimension individually. However, BVH traversal in robust mode is already conservative in the node intersection test, so I'm just wondering why you need even larger epsilons?

 

Thanks for the idea. 

Speaking of your question I assume you mean "conservative" as a ray not missing some triangles. In my application which is a sort a contact algorithm of the finite element analysis, when the ray almost hit the boundary of a surface but technically didn't intersect it, it should still be treated as intersected. Because the nonlinear equation solver becomes unstable when the small changes in the solution vector cause jumps of contact forces between two value (0 to 1 or 1 to 0) in consecutive iterations. 

0 Kudos
Reply