// intersect a ray with the mesh bool TXGrid3D::IntersectRay(const CVector3f& start, const CVector3f& end) { // pick rays m_rays.push_back(TXRay(start, end)); CVector3f dir; dir.Sub(start,end); int idir[3] = { fabs(dir.GetX()) < DBL_EPSILON ? 0 : (dir.GetX() > 0 ? 1 : -1), fabs(dir.GetY()) < DBL_EPSILON ? 0 : (dir.GetY() > 0 ? 1 : -1), fabs(dir.GetZ()) < DBL_EPSILON ? 0 : (dir.GetZ() > 0 ? 1 : -1) }; double dist = 0; CVector3f pos; pos.Sub(end, m_min); int ix = (int)floor((end.GetX() - m_min.GetX())/m_xstep), iy = (int)floor((end.GetY() - m_min.GetY())/m_ystep), iz = (int)floor((end.GetZ() - m_min.GetZ())/m_zstep); double tx = 1.0, ty = 1.0, tz = 1.0; // first cell ix = MIN(MAX(ix, 0), m_size-1); iy = MIN(MAX(iy, 0), m_size-1); iz = MIN(MAX(iz, 0), m_size-1); // intersection test, from end to start while ((dist < 1) && (ix >= 0) && (ix < m_size) &&(iy >= 0) && (iy < m_size) && (iz >= 0) && (iz < m_size)) { int csz = m_grid[ix][iy][iz].size(); for (int i=0; i<csz; i++) { TXGridTriangle* gt = m_grid[ix][iy][iz][i]; double rpdot = dir.Dot(gt->m_n); if (rpdot != 0) { CVector3f tmp; tmp.Sub(gt->m_t->m_v[0]->m_pos,end); double t = tmp.Dot(gt->m_n) / rpdot; if (t > DBL_EPSILON && t < 1) { CVector3f pt; pt.ScaleAdd(t,dir,end); CVector3f pt0,pt1,pt2; pt0.Sub(pt,gt->m_t->m_v[0]->m_pos); pt1.Sub(pt,gt->m_t->m_v[1]->m_pos); pt2.Sub(pt,gt->m_t->m_v[2]->m_pos); if (pt0.Dot(gt->m_en1)> -DBL_EPSILON && pt1.Dot(gt->m_en2)>-DBL_EPSILON && pt2.Dot(gt->m_en3)>-DBL_EPSILON) { m_rays[m_rays.size()-1].m_p = t; return true; } } } } // next cell if (idir[0] != 0) tx = (m_min.GetX() + (ix+(idir[0]+1)/2)*m_xstep - end.GetX()) / dir.GetX(); if (idir[1] != 0) ty = (m_min.GetY() + (iy+(idir[1]+1)/2)*m_ystep - end.GetY()) / dir.GetY(); if (idir[2] != 0) tz = (m_min.GetZ() + (iz+(idir[2]+1)/2)*m_zstep - end.GetZ()) / dir.GetZ(); if ((tx <= ty) && (tx <= tz)) { dist = tx, ix += idir[0]; if (ty == tx) iy += idir[1]; if (tz == tx) iz += idir[2]; } else if (ty <= tz) { dist = ty, iy += idir[1]; if (tz == ty) iz += idir[2]; } else dist = tz, iz += idir[2]; } return false; }