bool OctreeScene::Intersect(const Ray& ray, Intersection& intersection, void* additional_data) const { float min_t = ray.EffectRange().Max; const OctreeNode* current = m_GeometryTree.Root(); std::priority_queue<Octree::QueueElement> queue; Intersection hit; if (current->Extents().Intersect(ray, hit, additional_data)) queue.push(Octree::QueueElement(hit.Distance(), current)); while (!queue.empty() && queue.top().t < min_t) { current = queue.top().node; queue.pop(); if (current->IsLeaf()) { for (auto iter = current->Triangles().begin(); iter != current->Triangles().end(); ++iter) { if ((*iter)->Intersect(ray, hit, additional_data) && hit.Distance() < min_t) { min_t = hit.Distance(); intersection = hit; } } } else { for (unsigned i = 0; i < 8; ++i) if (current->ChildAt(i) != nullptr) if (current->ChildAt(i)->Extents().Intersect(ray, hit, additional_data)) queue.push(Octree::QueueElement(hit.Distance(), current->ChildAt(i))); } } if (min_t != ray.EffectRange().Max) return true; else return false; }
bool Plane::Intersect(const Ray& ray, Intersection& intersection, void* additional_data) const { float dir_norm = ray.Direction().DotProduct(m_Orientation); if (abs(dir_norm) < std::numeric_limits<float>::epsilon()) return false; float t = (m_Center - ray.Origin()).DotProduct(m_Orientation) / dir_norm; Range<float> range = ray.EffectRange(); if (Math::Contain(t, range)) { intersection.SetDistance(t); intersection.SetIntersectObject((IIntersectTarget*)this); intersection.SetTestObject(&ray); return true; } return false; }
bool AABB::Intersect(const Ray& ray, Intersection& intersection, void* additional_data) const { ++Profiler::numRayVolumeTestsPerFrame; Vector3 origin = ray.Origin(); Vector3 inversed_dir = ray.InvDirection(); Range<float> t, t_y, t_z; if (inversed_dir.X() >= 0) { t.Max = (m_MaxExtent.X() - origin.X()) * inversed_dir.X(); t.Min = (m_MinExtent.X() - origin.X()) * inversed_dir.X(); } else { t.Min = (m_MaxExtent.X() - origin.X()) * inversed_dir.X(); t.Max = (m_MinExtent.X() - origin.X()) * inversed_dir.X(); } if (inversed_dir.Y() >= 0) { t_y.Max = (m_MaxExtent.Y() - origin.Y()) * inversed_dir.Y(); t_y.Min = (m_MinExtent.Y() - origin.Y()) * inversed_dir.Y(); } else { t_y.Min = (m_MaxExtent.Y() - origin.Y()) * inversed_dir.Y(); t_y.Max = (m_MinExtent.Y() - origin.Y()) * inversed_dir.Y(); } if (t.Min > t_y.Max || t_y.Min > t.Max) return false; if (t.Min < t_y.Min) t.Min = t_y.Min; if (t.Max > t_y.Max) t.Max = t_y.Max; if (inversed_dir.Z() >= 0) { t_z.Max = (m_MaxExtent.Z() - origin.Z()) * inversed_dir.Z(); t_z.Min = (m_MinExtent.Z() - origin.Z()) * inversed_dir.Z(); } else { t_z.Min = (m_MaxExtent.Z() - origin.Z()) * inversed_dir.Z(); t_z.Max = (m_MinExtent.Z() - origin.Z()) * inversed_dir.Z(); } if (t.Min > t_z.Max || t_z.Min > t.Max) return false; if (t.Min < t_z.Min) t.Min = t_z.Min; if (t.Max > t_z.Max) t.Max = t_z.Max; Range<float> range = ray.EffectRange(); if (Math::Contain(t.Min, range)) intersection.SetDistance(t.Min); else if (Math::Contain(t.Max, range)) intersection.SetDistance(0.f); else if (range.Min > t.Min && range.Max < t.Max) intersection.SetDistance(0.f); else return false; intersection.SetIntersectObject((IIntersectTarget*)this); intersection.SetTestObject(&ray); return true; }