bool Raycast(const Ray &ray, HitInfo &outHit) override
{
float tHit;
if (!RayAABB(ray.origin, ray.dir, bbox.min, bbox.max, tHit))
return false;
glm::vec3 p = ray.origin + ray.dir * std::max(0.0f, tHit);
glm::ivec3 cell = PosToCell(p);
glm::vec3 step = glm::sign(ray.dir);
glm::vec3 tDelta = glm::abs(cellSize / ray.dir);
glm::vec3 next;
next.x = ((cell.x + (step.x > 0)) * cellSize.x + bbox.min.x - p.x) / ray.dir.x;
next.y = ((cell.y + (step.y > 0)) * cellSize.y + bbox.min.y - p.y) / ray.dir.y;
next.z = ((cell.z + (step.z > 0)) * cellSize.z + bbox.min.z - p.z) / ray.dir.z;
float bestT = FLT_MAX;
int bestIdx = -1;
while (cell.x >= 0 && cell.y >= 0 && cell.z >= 0 &&
cell.x < dims.x && cell.y < dims.y && cell.z < dims.z)
{
int idx = cell.x + dims.x * (cell.y + dims.y * cell.z);
for (int triIdx : cells[idx]) {
float t;
Triangle tri = Spatial::getTriangle(triIdx);
if (RayTriangle(ray, tri, t)) {
if (t < bestT) {
bestT = t;
bestIdx = triIdx;
}
}
}
if (next.x < next.y) {
if (next.x < next.z) {
cell.x += (int)step.x;
next.x += tDelta.x;
} else {
cell.z += (int)step.z;
next.z += tDelta.z;
}
} else {
if (next.y < next.z) {
cell.y += (int)step.y;
next.y += tDelta.y;
} else {
cell.z += (int)step.z;
next.z += tDelta.z;
}
}
}
if (bestIdx >= 0) {
outHit = {bestT, bestIdx};
return true;
}
return false;
}