float3 Ray::ClosestPoint(const Ray &other, float *d, float *d2) const { float u, u2; float3 closestPoint = Line::ClosestPointLineLine(pos, pos + dir, other.pos, other.pos + other.dir, &u, &u2); if (u < 0.f && u2 < 0.f) { closestPoint = ClosestPoint(other.pos, &u); float3 closestPoint2 = other.ClosestPoint(pos, &u2); if (closestPoint.DistanceSq(other.pos) <= closestPoint2.DistanceSq(pos)) { if (d) *d = u; if (d2) *d2 = 0.f; return closestPoint; } else { if (d) *d = 0.f; if (d2) *d2 = u2; return pos; } } else if (u < 0.f) { if (d) *d = 0.f; if (d2) { other.ClosestPoint(pos, &u2); *d2 = Max(0.f, u2); } return pos; } else if (u2 < 0.f) { float3 pt = ClosestPoint(other.pos, &u); u = Max(0.f, u); if (d) *d = u; if (d2) *d2 = 0.f; return pt; } else { if (d) *d = u; if (d2) *d2 = u2; return closestPoint; } }
void GizmoAxis::Update(Ray cameraRay, float scale, bool drag, const Vector3& camPos) { UI* ui = GetSubsystem<UI>(); // Do not select when UI has modal element if (ui->HasModalElement()) { selected = false; return; } Vector3 closest = cameraRay.ClosestPoint(axisRay); Vector3 projected = axisRay.Project(closest); d = axisRay.Distance(closest); t = (projected - axisRay.origin_).DotProduct(axisRay.direction_); // Determine the sign of d from a plane that goes through the camera position to the axis Plane axisPlane(camPos, axisRay.origin_, axisRay.origin_ + axisRay.direction_); if (axisPlane.Distance(closest) < 0.0) d = -d; // Update selected status only when not dragging if (!drag) { selected = (Abs(d) < axisMaxD * scale) && (t >= -axisMaxD * scale) && (t <= axisMaxT * scale); lastT = t; lastD = d; } }
Line Plane::NearEdge(Ray &ray) { Line lines[] = { Line(v0, v1), Line(v1, v2), Line(v2, v3), Line(v3, v0) }; int index = -1; float distance = 1e3f; for (int i = 0; i < 4; i++) { Ray rayEdge(lines[i].start, lines[i].end - lines[i].start); Vector3 closestPoint = ray.ClosestPoint(rayEdge); float dist = rayEdge.Distance(closestPoint); if (dist < distance) { distance = dist; index = i; } } return Line(lines[index].start, lines[index].end); }
vec Ray::ClosestPoint(const Ray &other, float &d, float &d2) const { Line::ClosestPointLineLine(pos, dir, other.pos, other.dir, d, d2); if (d < 0.f && d2 < 0.f) { vec closestPoint = ClosestPoint(other.pos, d); vec closestPoint2 = other.ClosestPoint(pos, d2); if (closestPoint.DistanceSq(other.pos) <= closestPoint2.DistanceSq(pos)) { d2 = 0.f; return closestPoint; } else { d = 0.f; return pos; } } else if (d < 0.f) { d = 0.f; other.ClosestPoint(pos, d2); d2 = Max(0.f, d2); return pos; } else if (d2 < 0.f) { vec pt = ClosestPoint(other.pos, d); d = Max(0.f, d); d2 = 0.f; return pt; } else { return GetPoint(d); } }