From 94469592f221c5b5725d748d47784356c0b1ef05 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 07:59:33 -0700 Subject: [PATCH] fix(objects): NaN guards in selectAt ray-sphere test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without these, NaN ray or NaN object position would short-circuit the disc < 0 early-out (NaN comparisons return false) and select the object at a garbage t — silently 'picking' arbitrary objects. --- tools/editor/object_placer.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tools/editor/object_placer.cpp b/tools/editor/object_placer.cpp index cecd9ee0..9f59c938 100644 --- a/tools/editor/object_placer.cpp +++ b/tools/editor/object_placer.cpp @@ -49,11 +49,25 @@ void ObjectPlacer::placeObject(const glm::vec3& position) { int ObjectPlacer::selectAt(const rendering::Ray& ray, float maxDist) { clearSelection(); + // Reject NaN ray — without this every disc < 0 short-circuit returns + // false and we'd 'hit' every object with garbage t values. + if (!std::isfinite(ray.origin.x) || !std::isfinite(ray.origin.y) || + !std::isfinite(ray.origin.z) || !std::isfinite(ray.direction.x) || + !std::isfinite(ray.direction.y) || !std::isfinite(ray.direction.z) || + !std::isfinite(maxDist)) { + return -1; + } float bestDist = maxDist; int bestIdx = -1; for (int i = 0; i < static_cast(objects_.size()); i++) { + // Skip objects with NaN position/scale — would feed NaN into the + // sphere test (NaN comparisons short-circuit to false → "hit"). + if (!std::isfinite(objects_[i].position.x) || + !std::isfinite(objects_[i].position.y) || + !std::isfinite(objects_[i].position.z) || + !std::isfinite(objects_[i].scale)) continue; // Simple sphere test (radius based on scale) float radius = 5.0f * objects_[i].scale; glm::vec3 oc = ray.origin - objects_[i].position;