EmbreeIntersector.cpp 10 KB

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