Настройка луча (начало координат, направление) и пересечения треугольника (без glm)

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

Я пытаюсь найти вектор, где линия пересекается с треугольником.

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

меры

  1. Отпроектировать координаты мыши
  2. Проверьте пересечение линии / треугольника

Отпроектировать координаты мыши

Я проверил источник glm::unproject и gluUnproject и создал эту функцию.

   pixel::CVector3 pixel::CVector::unproject(
    CVector2 inPosition,
    pixel::CShape window,
    pixel::matrix4 projectionMatrix,
    pixel::matrix4 modelViewMatrix,
    float depth
    )
{
    // transformation of normalized coordinates
    CVector4 inVector;
    inVector.x = (2.0f * inPosition.x) / window.width - 1.0f;
    inVector.y = (2.0f * inPosition.y) / window.height - 1.0f;
    inVector.z = 2.0f * depth - 1.0f;
    inVector.w = 1.0f;

    // multiply inverted matrix with vector
    CVector4 rayWorld = pixel::CVector::multMat4Vec4(pixel::CMatrix::invertMatrix(projectionMatrix * modelViewMatrix), inVector);

    CVector3 result;
    result.x = rayWorld.x / rayWorld.w;
    result.y = rayWorld.y / rayWorld.w;
    result.z = rayWorld.z / rayWorld.w;



    return result;
}

Проверка пересечения

pixel::CVector3 pixel::Ray::intersection(
    Ray ray,
    pixel::CVector3 v0,
    pixel::CVector3 v1,
    pixel::CVector3 v2
    )
{
    // compute normal
    CVector3 a, b, n;
    a = v1 - v0;
    b = v2 - v0;

    n = ray.direction.cross(b);

    // find determinant
    float det = a.dot(n);

    if (det < 0.000001f)
    {
        std::cout << "Ray intersecting with backface triangles \n";
        return pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
    }
    det = 1.0f / det;

    // calculate distance from vertex0 to ray origin
    CVector3 s = ray.origin - v0;
    float u = det * s.dot(n);

    if (u < -0.000001f || u > 1.f + 0.000001f)
    {
        std::cout << "U: Intersection outside of the triangle!\n";
        return pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
    }

    CVector3 r = s.cross(a);
    float v = det * ray.direction.dot(r);
    if (v < -0.000001f || u + v > 1.f + 0.000001f)
    {
        std::cout << "V/U: Intersection outside of triangle!\n";
        return pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
    }

    // distance from ray to triangle
    det = det *  b.dot(r);

    std::cout << "T: " << det << "\n";

    CVector3 endPosition;
    endPosition.x = ray.origin.x + (ray.direction.x * det);
    endPosition.y = ray.origin.y + (ray.direction.y * det);
    endPosition.z = ray.origin.z + (ray.direction.z * det);

    return endPosition;
}

использование

    if (event.button.button == SDL_BUTTON_RIGHT)
            {

                camera->setCameraActive();
                float mx = event.motion.x;
                float my = window->info.height - event.motion.y;
                // ray casting
                pixel::Ray ray;

                std::cout << "\n\n";

                    // near
                pixel::CVector3 rayNear = pixel::CVector::unproject(
                    pixel::CVector::vector2(mx, my),
                    pixel::CVector::shape2(window->info.internalWidth, window->info.internalHeight),
                    camera->camInfo.currentProjection,
                    camera->camInfo.currentView,
                    1.0f
                    );
                // far
                pixel::CVector3 rayFar = pixel::CVector::unproject(
                    pixel::CVector::vector2(mx, my),
                    pixel::CVector::shape2(window->info.internalWidth, window->info.internalHeight),
                    camera->camInfo.currentProjection,
                    camera->camInfo.currentView,
                    0.0f
                    );


                // normalized direction results in the same behavior
                ray.origin = cameraPosition;

                ray.direction = pixel::CVector::normalize(rayFar- rayNear);

                std::cout << "Raycast \n";
                std::cout << "Mouse Position: " << mx << " - " << my << "\n";
                std::cout << "Camera Position: " << ray.origin.x << " - " << ray.origin.y << " - " << ray.origin.z << "\n";
                std::cout << "Ray direction: " << ray.direction.x << " - " << ray.direction.y << " - " << ray.direction.z << "\n";


                pixel::CVector3 vertOne = pixel::CVector::vector3(0.0f, 0.0f, -300.0f);
                pixel::CVector3 vertTwo = pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
                pixel::CVector3 vertThree = pixel::CVector::vector3(300.0f, 0.0f, 0.0f);
                pixel::CVector3 vertFour = pixel::CVector::vector3(300.0f, 0.0f, -300.0f);


                pixel::CVector3 rayHit = pixel::Ray::intersection(ray, vertOne, vertTwo, vertThree);
                pixel::CVector3 rayHit2 = pixel::Ray::intersection(ray, vertThree, vertFour, vertOne);
                std::cout << "Ray hit: " << rayHit.x << " - " << rayHit.y << " - " << rayHit.z << "\n";
                std::cout << "Ray hit: " << rayHit2.x << " - " << rayHit2.y << " - " << rayHit2.z << "\n";
                std::cout << "--------------------\n";
                towerHouse->modelMatrix = pixel::CMatrix::translateMatrix(rayHit);

Выход

Поскольку я никогда не использовал glm::unproject или gluUnproject, я не знаю, как должен выглядеть нормальный вывод, но я получаю такие результаты:

Направление луча: 0.109035 -0.0380502 0.0114562

Не выглядит правильным для меня, но проверяя мой код по другим источникам (упомянутым выше), я не вижу ошибки /s.

Пересечение лучей работает в некоторых особых случаях (вращение камеры), и даже тогда я получаю пересечения, даже если я не нажимаю на пол. То же самое относится и к выходным данным пересечения, варьирующимся от попаданий на заднюю поверхность за пределы треугольника.

Все эти ошибки выглядят так, будто основным источником проблемы является непроекция.

Любые намеки в правильном направлении?

2 ответа

Решение

Это нигде не близко к ответу на этот вопрос, но это слишком сложно объяснить в комментариях или чате.

Прежде всего:

            // near
            pixel::CVector3 rayNear = pixel::CVector::raycast(
                pixel::CVector::vector2(mx, my),
                pixel::CVector::shape2(window->info.internalWidth, window->info.internalHeight),
                camera->camInfo.currentProjection,
                camera->camInfo.currentView,
                1.0f // WRONG
                );
            // far
            pixel::CVector3 rayFar = pixel::CVector::raycast(
                pixel::CVector::vector2(mx, my),
                pixel::CVector::shape2(window->info.internalWidth, window->info.internalHeight),
                camera->camInfo.currentProjection,
                camera->camInfo.currentView,
                0.0f // WRONG
                );

Ближний - это 0,0 в пространстве окна, а дальний - 1,0 (зависит от диапазона глубины, но если вы изменили диапазон глубины, вы уже должны это знать).

В вашей функции приведения лучей у вас есть:

CVector3 result;
result.x = rayWorld.x / rayWorld.w;
result.y = rayWorld.y / rayWorld.w;
result.z = rayWorld.z / rayWorld.w;

Есть шанс, что w == 0.0и результат пока не луч в это время... это позиция в объектном пространстве (не мире). Как правило, вы всегда будете работать с матрицами с хорошим поведением, но если вы когда-нибудь посмотрите на формальную реализацию UnProject (...) вы заметите, что они обрабатывают случай, когда w == 0.0 со специальным возвращаемым значением или установив флаг состояния.

            pixel::CVector3 vertOne = pixel::CVector::vector3(0.0f, 0.0f, -300.0f);
            pixel::CVector3 vertTwo = pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
            pixel::CVector3 vertThree = pixel::CVector::vector3(300.0f, 0.0f, 0.0f);
            pixel::CVector3 vertFour = pixel::CVector::vector3(300.0f, 0.0f, -300.0f);

В каком координатном пространстве находятся эти вершины? Предположительно объект-пространство, что означает, что если вы излучаете луч из точки зрения вашей камеры (определенной в мировом пространстве), которая проходит через точку на вашей дальней плоскости, и пытаетесь чаще проверять пересечение с треугольником в объектном пространстве чем не скучаешь. Это потому, что начало, масштаб и поворот для каждого из этих пространств могут отличаться. Вам нужно преобразовать эти точки в мировое пространство (ваш исходный код имел floor->modelMatrix это будет хорошо работать для этой цели), прежде чем попробовать этот тест.

Я выследил проблему и исправил ошибки. у меня были неправильные матрицы * матрица и матрица * операторы умножения вектора.

Другие вопросы по тегам