Какой самый быстрый способ найти точку пересечения между лучом и многоугольником? - PullRequest
3 голосов
/ 23 ноября 2008

Почти как вопрос. Ответы желательно в псевдокоде и ссылках. Правильный ответ должен ценить скорость над простотой.

Ответы [ 4 ]

4 голосов
/ 23 ноября 2008

См. Пересечения лучей, сегментов, плоскостей и треугольников в 3D . Вы можете найти способы триангуляции полигонов.

Если вам действительно нужно пересечение луча / многоугольника, то оно составляет 16,9 из Рендеринг в реальном времени (13,8 для 2-го издания).

Сначала мы вычисляем пересечение между лучом и плоскостью плойгон] pie_p, что легко сделать заменив x на луч.

 n_p DOT (o + td) + d_p = 0 <=> t = (-d_p - n_p DOT o) / (n_p DOT d)

Если знаменатель |n_p DOT d| < epsilon, где epsilon очень мало число, то луч считается параллельно плоскости многоугольника и нет пересечение происходит. В противном случае точка пересечения p луча и плоскость многоугольника вычисляется: p = o + td. После этого проблема решить, находится ли p внутри полигон уменьшен с трех до двух ... * Размеры 1022 *

См. Книгу для более подробной информации.

3 голосов
/ 23 ноября 2008
struct point
{
    float x
    float y
    float z
}

struct ray
{
    point R1
    point R2
}

struct polygon
{
    point P[]
    int count
}

float dotProduct(point A, point B)
{
    return A.x*B.x + A.y*B.y + A.z*B.z
}

point crossProduct(point A, point B)
{
    return point(A.y*B.z-A.z*B.y, A.z*B.x-A.x*B.z, A.x*B.y-A.y*B.x)
}

point vectorSub(point A, point B)
{
    return point(A.x-B.x, A.y-B.y, A.z-B.z) 
}

point scalarMult(float a, Point B)
{
    return point(a*B.x, a*B.y, a*B.z)
}

bool findIntersection(ray Ray, polygon Poly, point& Answer)
{
    point plane_normal = crossProduct(vectorSub(Poly.P[1], Poly.P[0]), vectorSub(Poly.P[2], Poly.P[0]))

    float denominator = dotProduct(vectorSub(Ray.R2, Poly.P[0]), plane_normal)

    if (denominator == 0) { return FALSE } // ray is parallel to the polygon

    float ray_scalar = dotProduct(vectorSub(Poly.P[0], Ray.R1), plane_normal)

    Answer = vectorAdd(Ray.R1, scalarMult(ray_scalar, Ray.R2))

    // verify that the point falls inside the polygon

    point test_line = vectorSub(Answer, Poly.P[0])
    point test_axis = crossProduct(plane_normal, test_line)

    bool point_is_inside = FALSE

    point test_point = vectorSub(Poly.P[1], Answer)
    bool prev_point_ahead = (dotProduct(test_line, test_point) > 0)
    bool prev_point_above = (dotProduct(test_axis, test_point) > 0)

    bool this_point_ahead
    bool this_point_above

    int index = 2;
    while (index < Poly.count)
    {
        test_point = vectorSub(Poly.P[index], Answer)
        this_point_ahead = (dotProduct(test_line, test_point) > 0)

        if (prev_point_ahead OR this_point_ahead)
        {
            this_point_above = (dotProduct(test_axis, test_point) > 0)

            if (prev_point_above XOR this_point_above)
            {
                point_is_inside = !point_is_inside
            }
        }

        prev_point_ahead = this_point_ahead
        prev_point_above = this_point_above
        index++
    }

    return point_is_inside
}
1 голос
/ 23 ноября 2008

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

  • Введение в Ray Tracing, ed. Эндрю С. Гласснер, ISBN 0122861604
0 голосов
/ 11 февраля 2014
function Collision(PlaneOrigin,PlaneDirection,RayOrigin,RayDirection)
    return RayOrigin-RayDirection*Dot(PlaneDirection,RayOrigin-PlaneOrigin)/Dot(PlaneDirection,RayDirection)
end

(PlaneDirection - единичный вектор, перпендикулярный плоскости)

...