EmbreeIntersector.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. #include "EmbreeIntersector.h"
  2. // Implementation
  3. #include "../EPS.h"
  4. IGL_INLINE igl::embree::EmbreeIntersector::EmbreeIntersector()
  5. :
  6. //scene(NULL),
  7. geomID(0),
  8. vertices(NULL),
  9. triangles(NULL),
  10. initialized(false),
  11. device(igl::embree::EmbreeDevice::get_device())
  12. {
  13. }
  14. IGL_INLINE igl::embree::EmbreeIntersector::EmbreeIntersector(
  15. const EmbreeIntersector &)
  16. :// To make -Weffc++ happy
  17. //scene(NULL),
  18. geomID(0),
  19. vertices(NULL),
  20. triangles(NULL),
  21. initialized(false)
  22. {
  23. assert(false && "Embree: Copying EmbreeIntersector is not allowed");
  24. }
  25. IGL_INLINE igl::embree::EmbreeIntersector & igl::embree::EmbreeIntersector::operator=(
  26. const EmbreeIntersector &)
  27. {
  28. assert(false && "Embree: Assigning an EmbreeIntersector is not allowed");
  29. return *this;
  30. }
  31. IGL_INLINE void igl::embree::EmbreeIntersector::init(
  32. const PointMatrixType& V,
  33. const FaceMatrixType& F,
  34. bool isStatic)
  35. {
  36. std::vector<const PointMatrixType*> Vtemp;
  37. std::vector<const FaceMatrixType*> Ftemp;
  38. std::vector<int> masks;
  39. Vtemp.push_back(&V);
  40. Ftemp.push_back(&F);
  41. masks.push_back(0xFFFFFFFF);
  42. init(Vtemp,Ftemp,masks,isStatic);
  43. }
  44. IGL_INLINE void igl::embree::EmbreeIntersector::init(
  45. const std::vector<const PointMatrixType*>& V,
  46. const std::vector<const FaceMatrixType*>& F,
  47. const std::vector<int>& masks,
  48. bool isStatic)
  49. {
  50. if(initialized)
  51. deinit();
  52. if(V.size() == 0 || F.size() == 0)
  53. {
  54. std::cerr << "Embree: No geometry specified!";
  55. return;
  56. }
  57. RTCBuildQuality buildQuality = isStatic ? RTC_BUILD_QUALITY_HIGH : RTC_BUILD_QUALITY_MEDIUM;
  58. // create a scene
  59. scene = rtcNewScene(device);
  60. rtcSetSceneFlags(scene, RTC_SCENE_FLAG_ROBUST);
  61. rtcSetSceneBuildQuality(scene, buildQuality);
  62. for(int g=0;g<(int)V.size();g++)
  63. {
  64. // create triangle mesh geometry in that scene
  65. RTCGeometry geom_0 = rtcNewGeometry (device, RTC_GEOMETRY_TYPE_TRIANGLE);
  66. rtcSetGeometryBuildQuality(geom_0,buildQuality);
  67. rtcSetGeometryTimeStepCount(geom_0,1);
  68. geomID = rtcAttachGeometry(scene,geom_0);
  69. rtcReleaseGeometry(geom_0);
  70. // fill vertex buffer
  71. vertices = (Vertex*)rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_VERTEX,0,RTC_FORMAT_FLOAT3,4*sizeof(float),V[g]->rows());
  72. for(int i=0;i<(int)V[g]->rows();i++)
  73. {
  74. vertices[i].x = (float)V[g]->coeff(i,0);
  75. vertices[i].y = (float)V[g]->coeff(i,1);
  76. vertices[i].z = (float)V[g]->coeff(i,2);
  77. }
  78. // fill triangle buffer
  79. triangles = (Triangle*) rtcSetNewGeometryBuffer(geom_0,RTC_BUFFER_TYPE_INDEX,0,RTC_FORMAT_UINT3,3*sizeof(int),F[g]->rows());
  80. for(int i=0;i<(int)F[g]->rows();i++)
  81. {
  82. triangles[i].v0 = (int)F[g]->coeff(i,0);
  83. triangles[i].v1 = (int)F[g]->coeff(i,1);
  84. triangles[i].v2 = (int)F[g]->coeff(i,2);
  85. }
  86. rtcSetGeometryMask(geom_0,masks[g]);
  87. rtcCommitGeometry(geom_0);
  88. }
  89. rtcCommitScene(scene);
  90. if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
  91. std::cerr << "Embree: An error occurred while initializing the provided geometry!" << std::endl;
  92. #ifdef IGL_VERBOSE
  93. else
  94. std::cerr << "Embree: geometry added." << std::endl;
  95. #endif
  96. initialized = true;
  97. }
  98. IGL_INLINE igl::embree::EmbreeIntersector
  99. ::~EmbreeIntersector()
  100. {
  101. if(initialized)
  102. deinit();
  103. igl::embree::EmbreeDevice::release_device();
  104. }
  105. IGL_INLINE void igl::embree::EmbreeIntersector::deinit()
  106. {
  107. if(device && scene)
  108. {
  109. rtcReleaseScene(scene);
  110. if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
  111. {
  112. std::cerr << "Embree: An error occurred while resetting!" << std::endl;
  113. }
  114. #ifdef IGL_VERBOSE
  115. else
  116. {
  117. std::cerr << "Embree: geometry removed." << std::endl;
  118. }
  119. #endif
  120. }
  121. }
  122. IGL_INLINE bool igl::embree::EmbreeIntersector::intersectRay(
  123. const Eigen::RowVector3f& origin,
  124. const Eigen::RowVector3f& direction,
  125. Hit<float> & hit,
  126. float tnear,
  127. float tfar,
  128. int mask) const
  129. {
  130. RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
  131. ray.ray.flags = 0;
  132. createRay(ray, origin,direction,tnear,tfar,mask);
  133. // shot ray
  134. {
  135. rtcIntersect1(scene,&ray);
  136. ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
  137. ray.hit.Ng_y = -ray.hit.Ng_y;
  138. ray.hit.Ng_z = -ray.hit.Ng_z;
  139. }
  140. #ifdef IGL_VERBOSE
  141. if(rtcGetDeviceError (device) != RTC_ERROR_NONE)
  142. std::cerr << "Embree: An error occurred while resetting!" << std::endl;
  143. #endif
  144. if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
  145. {
  146. hit.id = ray.hit.primID;
  147. hit.gid = ray.hit.geomID;
  148. hit.u = ray.hit.u;
  149. hit.v = ray.hit.v;
  150. hit.t = ray.ray.tfar;
  151. return true;
  152. }
  153. return false;
  154. }
  155. IGL_INLINE bool igl::embree::EmbreeIntersector::intersectBeam(
  156. const Eigen::RowVector3f& origin,
  157. const Eigen::RowVector3f& direction,
  158. Hit<float> & hit,
  159. float tnear,
  160. float tfar,
  161. int mask,
  162. int geoId,
  163. bool closestHit,
  164. unsigned int samples) const
  165. {
  166. bool hasHit = false;
  167. Hit<float> bestHit;
  168. if(closestHit)
  169. bestHit.t = std::numeric_limits<float>::max();
  170. else
  171. bestHit.t = 0;
  172. if((intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1)))
  173. {
  174. bestHit = hit;
  175. hasHit = true;
  176. }
  177. // sample points around actual ray (conservative hitcheck)
  178. const float eps= 1e-5;
  179. Eigen::RowVector3f up(0,1,0);
  180. if (direction.cross(up).norm() < eps) up = Eigen::RowVector3f(1,0,0);
  181. Eigen::RowVector3f offset = direction.cross(up).normalized();
  182. Eigen::Matrix3f rot = Eigen::AngleAxis<float>(2*3.14159265358979/samples,direction).toRotationMatrix();
  183. for(int r=0;r<(int)samples;r++)
  184. {
  185. if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) &&
  186. ((closestHit && (hit.t < bestHit.t)) ||
  187. (!closestHit && (hit.t > bestHit.t))) &&
  188. (hit.gid == geoId || geoId == -1))
  189. {
  190. bestHit = hit;
  191. hasHit = true;
  192. }
  193. offset = rot*offset.transpose();
  194. }
  195. hit = bestHit;
  196. return hasHit;
  197. }
  198. IGL_INLINE bool
  199. igl::embree::EmbreeIntersector
  200. ::intersectRay(
  201. const Eigen::RowVector3f& origin,
  202. const Eigen::RowVector3f& direction,
  203. std::vector<Hit<float> > &hits,
  204. int& num_rays,
  205. float tnear,
  206. float tfar,
  207. int mask) const
  208. {
  209. num_rays = 0;
  210. hits.clear();
  211. int last_id0 = -1;
  212. double self_hits = 0;
  213. // This epsilon is directly correleated to the number of missed hits, smaller
  214. // means more accurate and slower
  215. //const double eps = DOUBLE_EPS;
  216. const double eps = FLOAT_EPS;
  217. double min_t = tnear;
  218. bool large_hits_warned = false;
  219. RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
  220. ray.ray.flags = 0;
  221. createRay(ray,origin,direction,tnear,tfar,mask);
  222. while(true)
  223. {
  224. ray.ray.tnear = min_t;
  225. ray.ray.tfar = tfar;
  226. ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
  227. ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
  228. ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
  229. num_rays++;
  230. {
  231. rtcIntersect1(scene,&ray);
  232. ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
  233. ray.hit.Ng_y = -ray.hit.Ng_y;
  234. ray.hit.Ng_z = -ray.hit.Ng_z;
  235. }
  236. if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
  237. {
  238. // Hit self again, progressively advance
  239. if(ray.hit.primID == last_id0 || ray.ray.tfar <= min_t)
  240. {
  241. // push min_t a bit more
  242. //double t_push = pow(2.0,self_hits-4)*(hit.t<eps?eps:hit.t);
  243. double t_push = pow(2.0,self_hits)*eps;
  244. #ifdef IGL_VERBOSE
  245. std::cerr<<" t_push: "<<t_push<<std::endl;
  246. #endif
  247. //o = o+t_push*d;
  248. min_t += t_push;
  249. self_hits++;
  250. }
  251. else
  252. {
  253. Hit<float> hit;
  254. hit.id = ray.hit.primID;
  255. hit.gid = ray.hit.geomID;
  256. hit.u = ray.hit.u;
  257. hit.v = ray.hit.v;
  258. hit.t = ray.ray.tfar;
  259. hits.push_back(hit);
  260. #ifdef IGL_VERBOSE
  261. std::cerr<<" t: "<<hit.t<<std::endl;
  262. #endif
  263. // Instead of moving origin, just change min_t. That way calculations
  264. // all use exactly same origin values
  265. min_t = ray.ray.tfar;
  266. // reset t_scale
  267. self_hits = 0;
  268. }
  269. last_id0 = ray.hit.primID;
  270. }
  271. else
  272. break; // no more hits
  273. if(hits.size()>1000 && !large_hits_warned)
  274. {
  275. std::cout<<"Warning: Large number of hits..."<<std::endl;
  276. std::cout<<"[ ";
  277. for(std::vector<Hit<float>>::iterator hit = hits.begin(); hit != hits.end();hit++)
  278. {
  279. std::cout<<(hit->id+1)<<" ";
  280. }
  281. std::cout.precision(std::numeric_limits< double >::digits10);
  282. std::cout<<"[ ";
  283. for(std::vector<Hit<float>>::iterator hit = hits.begin(); hit != hits.end(); hit++)
  284. {
  285. std::cout<<(hit->t)<<std::endl;
  286. }
  287. std::cout<<"]"<<std::endl;
  288. large_hits_warned = true;
  289. return hits.empty();
  290. }
  291. }
  292. return hits.empty();
  293. }
  294. IGL_INLINE bool
  295. igl::embree::EmbreeIntersector
  296. ::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit<float> &hit, int mask) const
  297. {
  298. RTCRayHit ray; // EMBREE_FIXME: use RTCRay for occlusion rays
  299. ray.ray.flags = 0;
  300. createRay(ray,a,ab,0,1.0,mask);
  301. {
  302. rtcIntersect1(scene,&ray);
  303. ray.hit.Ng_x = -ray.hit.Ng_x; // EMBREE_FIXME: only correct for triangles,quads, and subdivision surfaces
  304. ray.hit.Ng_y = -ray.hit.Ng_y;
  305. ray.hit.Ng_z = -ray.hit.Ng_z;
  306. }
  307. if((unsigned)ray.hit.geomID != RTC_INVALID_GEOMETRY_ID)
  308. {
  309. hit.id = ray.hit.primID;
  310. hit.gid = ray.hit.geomID;
  311. hit.u = ray.hit.u;
  312. hit.v = ray.hit.v;
  313. hit.t = ray.ray.tfar;
  314. return true;
  315. }
  316. return false;
  317. }
  318. IGL_INLINE void
  319. igl::embree::EmbreeIntersector
  320. ::createRay(RTCRayHit& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
  321. {
  322. ray.ray.org_x = origin[0];
  323. ray.ray.org_y = origin[1];
  324. ray.ray.org_z = origin[2];
  325. ray.ray.dir_x = direction[0];
  326. ray.ray.dir_y = direction[1];
  327. ray.ray.dir_z = direction[2];
  328. ray.ray.tnear = tnear;
  329. ray.ray.tfar = tfar;
  330. ray.ray.id = RTC_INVALID_GEOMETRY_ID;
  331. ray.ray.mask = mask;
  332. ray.ray.time = 0.0f;
  333. ray.hit.geomID = RTC_INVALID_GEOMETRY_ID;
  334. ray.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
  335. ray.hit.primID = RTC_INVALID_GEOMETRY_ID;
  336. }