Учитывая ограничительную рамку и строку (две точки), определите, пересекает ли строка поле

Учитывая ограничительную рамку, с определениями как bounds.min.(x/y/z), bounds.max.(x/y/z), и две точки в 3D пространстве (выраженный как Vector3 объекты), как я могу определить, пересекает ли строка, сделанная двумя точками, ограничительную рамку?

6
задан ThinkingStiff 3 February 2013 в 05:40
поделиться

4 ответа

Реализация на C ++ доступна онлайн здесь: Line Box Intersection ( http://www.3dkingdoms.com/weekly/weekly.php?a = 3 )

Еще одна ссылка со ссылками (и кодом) для множества тестов пересечения: http://www.realtimerendering.com/intersections.html

Если вы хотите узнать больше о тестах на пересечение, вот библия: Обнаружение столкновений в реальном времени (Amazon)

РЕДАКТИРОВАТЬ: алгоритм в этой статье («Эффективный и надежный алгоритм пересечения лучевых ящиков», Эми Уильямс, Стив Баррус и Р. Кейт Морли и Питер Ширли; журнал графики, графических процессоров и игровых инструментов, том 10 (1), 49-54, 2005) выглядит особенно лаконично и поставляется с исходным кодом (C ++). .

10
ответ дан 8 December 2019 в 04:51
поделиться

Вот код, который, похоже, работает, преобразованный из ответа Грега S в C #:

bool CheckLineBox(Vector3 B1, Vector3 B2, Vector3 L1, Vector3 L2, ref Vector3 Hit)
{
    if (L2.x < B1.x && L1.x < B1.x) return false;
    if (L2.x > B2.x && L1.x > B2.x) return false;
    if (L2.y < B1.y && L1.y < B1.y) return false;
    if (L2.y > B2.y && L1.y > B2.y) return false;
    if (L2.z < B1.z && L1.z < B1.z) return false;
    if (L2.z > B2.z && L1.z > B2.z) return false;
    if (L1.x > B1.x && L1.x < B2.x &&
        L1.y > B1.y && L1.y < B2.y &&
        L1.z > B1.z && L1.z < B2.z)
    {
        Hit = L1;
        return true;
    }
    if ((GetIntersection(L1.x - B1.x, L2.x - B1.x, L1, L2, ref Hit) && InBox(Hit, B1, B2, 1))
      || (GetIntersection(L1.y - B1.y, L2.y - B1.y, L1, L2, ref Hit) && InBox(Hit, B1, B2, 2))
      || (GetIntersection(L1.z - B1.z, L2.z - B1.z, L1, L2, ref Hit) && InBox(Hit, B1, B2, 3))
      || (GetIntersection(L1.x - B2.x, L2.x - B2.x, L1, L2, ref Hit) && InBox(Hit, B1, B2, 1))
      || (GetIntersection(L1.y - B2.y, L2.y - B2.y, L1, L2, ref Hit) && InBox(Hit, B1, B2, 2))
      || (GetIntersection(L1.z - B2.z, L2.z - B2.z, L1, L2, ref Hit) && InBox(Hit, B1, B2, 3)))
        return true;

    return false;
}

bool GetIntersection(float fDst1, float fDst2, Vector3 P1, Vector3 P2, ref Vector3 Hit)
{
    if ((fDst1 * fDst2) >= 0.0f) return false;
    if (fDst1 == fDst2) return false;
    Hit = P1 + (P2 - P1) * (-fDst1 / (fDst2 - fDst1));
    return true;
}

bool InBox(Vector3 Hit, Vector3 B1, Vector3 B2, int Axis)
{
    if (Axis == 1 && Hit.z > B1.z && Hit.z < B2.z && Hit.y > B1.y && Hit.y < B2.y) return true;
    if (Axis == 2 && Hit.z > B1.z && Hit.z < B2.z && Hit.x > B1.x && Hit.x < B2.x) return true;
    if (Axis == 3 && Hit.x > B1.x && Hit.x < B2.x && Hit.y > B1.y && Hit.y < B2.y) return true;
    return false;
}
5
ответ дан 8 December 2019 в 04:51
поделиться

Вы можете представить ограничивающую рамку в виде 12 треугольников (по 2 на каждую из 6 граней). Затем вы можете проверить пересечение вашей линии с каждым из них. У меня есть функция пересечения линий и треугольников, но она была написана для моего собственного программного движка рендеринга, а не для D3D. Могу попробовать конвертировать, если нужен код.

1
ответ дан 8 December 2019 в 04:51
поделиться

Вот один из способов сделать это, если вы хотите произвести вычисления самостоятельно: пересечь линию с каждой из 6 плоскостей, созданных ограничивающей рамкой.

Векторное представление линии: X = B + t * D, где B - кортеж (x, y, z) базовой точки (скажем, вашей первой точки), а D - направление линии, снова выражается как кортеж (dx, dy, dz). Вы получаете направление, вычитая одну из точек из другой, поэтому, если у вас есть точки P1 (x1, y1, z1) и P2 (x2, y2, z2), тогда D = P2 - P1 и B = P1, то есть D = (x2 - x1, y2-y1, z2-z1). Назовем элементы этого вектора dx, dy и dz.

Параметрическое представление плоскости: x + y + z = c. Итак, преобразуйте ограничивающую рамку в это представление, а затем используйте параметрическое представление вашей линии, например три уравнения x = x1 + t dx, y = y1 + t dy, z = y1 + t * dz, чтобы заменить x, y и z в уравнение плоскости. Решить для t.Поскольку каждая из ваших 6 плоскостей будет параллельна плоскости, созданной двумя осями, ваша проблема станет проще; например, для плоскости, параллельной плоскости, созданной осями x и y, ваше плоское уравнение просто принимает вид z = c, тогда как c - это координата z одной из ваших точек ограничивающего прямоугольника и так далее.

Теперь используйте t, чтобы вычислить точку пересечения прямой с вашей плоскостью. (Если t <0 или> 1, тогда ваша линия пересекает ВНЕШНЕЕ P1-P2, если t> = 0 и t <= 1, тогда ваша линия пересекает плоскость где-то между P1 и P2)

Теперь вы еще не сделано. Уравнение плоскости дает вам плоскость, а не прямоугольник, поэтому точка пересечения с плоскостью может фактически находиться ВНЕ вашего прямоугольника, но поскольку теперь у вас есть координаты вашего пересечения (x = x1 + t * dx и т. Д.), вы можете легко увидеть, находится ли эта точка внутри прямоугольника вашего ограничивающего прямоугольника. Теперь ваша проблема сводится к проверке, находится ли точка в 2D-пространстве внутри прямоугольника ограничивающей рамки, что тривиально проверить.

Конечно, первое, что вы должны сделать, если вы действительно используете это решение, - это проверить, выровнена ли линия также по одной оси, потому что в этом случае ваш код пересечения становится тривиальным, и он также решает проблему линия, не пересекающая некоторые плоскости, например огромные или крошечные числа t, может быть, даже переполнение или недостаточное количество.

Могу поспорить, есть более быстрые способы сделать это, но это сработает.

6
ответ дан 8 December 2019 в 04:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: