void Octant::GetDrawablesInternal(RayOctreeQuery& query) const { float octantDist = query.ray_.HitDistance(cullingBox_); if (octantDist >= query.maxDistance_) return; if (drawables_.Size()) { Drawable** start = const_cast<Drawable**>(&drawables_[0]); Drawable** end = start + drawables_.Size(); while (start != end) { Drawable* drawable = *start++; if ((drawable->GetDrawableFlags() & query.drawableFlags_) && (drawable->GetViewMask() & query.viewMask_)) drawable->ProcessRayQuery(query, query.result_); } } for (unsigned i = 0; i < NUM_OCTANTS; ++i) { if (children_[i]) children_[i]->GetDrawablesInternal(query); } }
void Octree::RaycastSingle(RayOctreeQuery& query) const { PROFILE(Raycast); query.result_.Clear(); rayQueryDrawables_.Clear(); GetDrawablesOnlyInternal(query, rayQueryDrawables_); // Sort by increasing hit distance to AABB for (PODVector<Drawable*>::Iterator i = rayQueryDrawables_.Begin(); i != rayQueryDrawables_.End(); ++i) { Drawable* drawable = *i; drawable->SetSortValue(query.ray_.HitDistance(drawable->GetWorldBoundingBox())); } Sort(rayQueryDrawables_.Begin(), rayQueryDrawables_.End(), CompareDrawables); // Then do the actual test according to the query, and early-out as possible float closestHit = M_INFINITY; for (PODVector<Drawable*>::Iterator i = rayQueryDrawables_.Begin(); i != rayQueryDrawables_.End(); ++i) { Drawable* drawable = *i; if (drawable->GetSortValue() < Min(closestHit, query.maxDistance_)) { unsigned oldSize = query.result_.Size(); drawable->ProcessRayQuery(query, query.result_); if (query.result_.Size() > oldSize) closestHit = Min(closestHit, query.result_.Back().distance_); } else break; } if (query.result_.Size() > 1) { Sort(query.result_.Begin(), query.result_.End(), CompareRayQueryResults); query.result_.Resize(1); } }