Треугольники с трассировкой лучей

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

Вот основной алгоритм, насколько я понимаю:

  1. Сначала определите, пересекает ли луч даже плоскость, на которой находится треугольник.
  2. Обрежьте все точки так, чтобы они находились на той же плоскости, что и треугольник (например, на плоскости xy).
  3. Определите, попадает ли потенциальная точка пересечения внутрь или за пределы треугольника, основываясь на количестве ребер многоугольника, которые вы пересекаете при отправке луча в произвольном направлении вдоль новой плоскости.

Теперь вот моя реализация этого (в частности, первая точка):

public Vector getIntersectionVector(Ray ray)
{
    Vector planeIntersectionVector = getPlaneIntersectionVector(ray, getPlaneNormal());
    if (planeIntersectionVector != null)
    {
        if (isIntersectionVectorInsideTriangle(planeIntersectionVector))
        {
            return planeIntersectionVector;
        }
        else
        {
            return null;
        }
    }
    else
    {
        return null;
    }
}

Где getPlaceIntersectionVector():

private Vector getPlaneIntersectionVector(Ray ray, Vector planeNormal)
{
    double vd = planeNormal.dotProduct(ray.getDirection());
    //(p_n \dot r_d) == 0, parallel. (p_n \dot r_d) > 0 Plane normal pointing away from ray.
    if (vd >= 0)
    {
        return null;
    }
    double distance = planeNormal.distance(0d, 0d, 0d);
    double vo = -(planeNormal.dotProduct(ray.getOrigin()) + distance);
    double intersectionDistance = vo / vd;

    //intersectionDistance <= 0 means the "intersection" is behind the ray, so not a real intersection
    return (intersectionDistance <= 0) ? null : ray.getLocation(intersectionDistance);
} 

Что в основном пытается имитировать это:
 Пересечение плоскостей

И это:
 Пересечение лучей

Где t - расстояние вдоль луча, на которое попадает точка, r o - начало луча, r d - направление луча, p n относится к плоскости, перпендикулярной треугольнику / плоскости, а d - это расстояние от плоскости, на которой находится треугольник, до начала координат (0,0,0)

Я что делаю неправильно? Когда я отправляю луч из первого пикселя изображения (0,0), я вижу, что intersectionDistance (или t) почти 1100, что интуитивно кажется мне неправильным. Думаю, точка пересечения будет намного ближе.

Вот соответствующие данные: начало луча (0,0,1), направление луча примерно (0.000917, -0.4689, -0.8833).
Треугольник имеет вершины как (-0.2, 0.1, 0.1), (-0.2, -0.5, 0.2), (-0.2, 0.1, -0.3), что делает плоскость нормальной (-1, 0, 0).
Согласно моему коду, луч пересекает плоскость 1090 расстояние, которое, как я упоминал ранее, кажется мне неправильным. Сцена только от -1,0 до 1,0 во всех направлениях, что означает, что пересечение очень-очень далеко.
Я неправильно делаю пересечение плоскостей?

Пожалуйста, дайте мне знать, где уточнить моменты, и если вам нужна дополнительная информация.


person Cache Staheli    schedule 12.11.2016    source источник


Ответы (2)


Проблема в этой строке:

double distance = planeNormal.distance(0d, 0d, 0d);

Плоскость определяется нормалью и расстоянием от плоскости до начала координат. Расстояние вектора от начала координат - это длина вектора, поэтому то, что вы вычисляете, - это просто длина нормали к плоскости (которая всегда будет равна 1,0, если она была нормализована).

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

Итак, определите свою функцию примерно так:

private Vector getPlaneIntersectionVector(Ray ray, Vector planeNormal, double planeDistance)

и назовите это примерно так:

Vector planeIntersectionVector = getPlaneIntersectionVector(ray, getPlaneNormal(), getPlaneDistance());

Тогда вы можете вычислить vo следующим образом:

double vo = -(planeNormal.dotProduct(ray.getOrigin()) + planeDistance);
person samgak    schedule 12.11.2016
comment
Предположим, я определил плоскость по нормали треугольника. Как мне в этом случае узнать расстояние от плоскости до начала координат? Из этого ответа я подумал, что это просто скалярное произведение между нормалью и вектором в плоскости (в в данном случае одна из вершин), но это кажется неправильным, потому что теперь пересечение составляет около 218. - person Cache Staheli; 12.11.2016
comment
Я думал, что это просто скалярное произведение между нормалью и вектором в плоскости - это должно быть правильно. Дважды проверьте, что ваш нормальный вектор плоскости нормализован - person samgak; 12.11.2016
comment
Собственно, вы уверены, что результат неверный? Расстояние пересечения составляет в направлении луча, а не расстояние до ближайшей точки на плоскости от начала луча. Поскольку ваш луч почти перпендикулярен нормали к плоскости (он имеет значение только 0,000917 в направлении нормали плоскости), вам придется пройти довольно далеко в этом направлении, прежде чем вы пересечетесь. - person samgak; 12.11.2016
comment
Хорошая точка зрения. Думаю, тогда это может быть правильно. Спасибо! Это в основном решило проблему, с которой я столкнулся на данный момент. - person Cache Staheli; 13.11.2016

Немного другой подход:

Пусть вершины треугольника равны V0, V1, V2
Векторы ребер равны

A = V1-V0
B = V2 - V0

У Рэя есть параметрическое уравнение (как вы писали)

P = R0 + t * Rd

С другой стороны, точка пересечения имеет параметрические координаты u, v в плоскости треугольника.

P = V0 + u * A + v * B

Таким образом, вы можете написать систему из трех линейных уравнений для координат x, y, z и решить ее для t, u, v. Если определитель ius не равен нулю (луч не параллелен плоскости), а t >=0 и u, v, u+v лежат в диапазоне 0..1, то P находится внутри треугольника.

R0.X + t * Rd.X = V0.X + u * A.X + v * B.X
R0.Y + t * Rd.Y = V0.Y + u * A.Y + v * B.Y
R0.Z + t * Rd.Z = V0.Z + u * A.Z + v * B.Z
person MBo    schedule 12.11.2016