Создание 'Ray' для raypicking не полностью работает

Я пытаюсь реализовать «Raypicker» для выбора объектов в моем проекте. Я не совсем понимаю, как это реализовать, но концептуально понимаю, как это должно работать. Я пытался узнать, как это сделать, но большинство руководств, которые я нахожу, проходят мимо моей головы. Мой текущий код основан на одном из недавних руководств, которые я нашел здесь.

После нескольких часов исправлений я пришел к выводу, что проблема, с которой я столкнулся с моим raypicker, в первую очередь связана с созданием луча. Если я заменю/жестко запрограммирую свои ближние/дальние плоскости координатой, которая, несомненно, будет находиться в области треугольника, средство выбора идентифицирует ее правильно.

Моя проблема заключается в следующем: создание моего луча, похоже, не полностью учитывает мою текущую камеру или перспективу, поэтому вращение камеры не влияет на то, где находится моя мышь. Я считаю, что для исправления этого мне нужно что-то вроде использования gluUnProject() или что-то в этом роде, но всякий раз, когда я использовал это, возвращаемые координаты x, y, z были бы невероятно малы,

Мое текущее создание луча - беспорядок. Я пытался использовать методы, которые изначально предлагались другими, но казалось, что какой бы метод я ни пробовал, он никогда не работал с моей функцией выбора/пересечения.

Вот код для создания моего луча:

void oglWidget::mousePressEvent(QMouseEvent *event)
{   

    QVector3D nearP = QVector3D(event->x()+camX, -event->y()-camY, -1.0);
    QVector3D farP = QVector3D(event->x()+camX, -event->y()-camY, 1.0);

    int i = -1;
    for (int x = 0; x < tileCount; x++)
    {
        bool rayInter = intersect(nearP, farP, tiles[x]->vertices);
        if (rayInter == true)
            i = x;
    }
    if (i != -1)
    {
        tiles[i]->showSelection();
    }
    else
    {
        for (int x = 0; x < tileCount; x++)
            tiles[x]->hideSelection();
    }
    //tiles[0]->showSelection();
}

Повторяю. Раньше я загружал окно просмотра, матрицы модели и проекции и отменял проекцию координат мыши, но в окне с разрешением 1920 x 1080 все, что я получаю, это значения в диапазоне от -2 до 2 для xy. & z для каждого события мыши, поэтому я пробую этот метод, но этот метод не работает с вращением и масштабированием камеры.

Я не хочу выбирать цвет пикселей, потому что кто знает, что мне может понадобиться эта техника позже, и я бы не хотел сдаваться после того количества усилий, которые я приложил до сих пор.


person Yattabyte    schedule 06.02.2015    source источник
comment
Может кто-нибудь показать мне, что я делаю неправильно? Я был в этом в течение нескольких дней ни к чему! Я даже пробовал разные комбинации проецирования и непроецирования по отношению к мыши и вершинам, но ничего не работает должным образом.   -  person Yattabyte    schedule 07.02.2015
comment
Вы знаете, вы можете реализовать средство выбора, отрисовывая свою сцену также в другой буфер, где вместо рисования цветов вы рисуете идентификаторы объектов в буфере. Чтобы выяснить, на какой объект вы нажали, все, что вам нужно сделать, это прочитать идентификатор объекта из буфера. Это выгодно, потому что он будет идеальным для пикселей, а также будет учитывать все, что вы делаете в вершинном шейдере, без дополнительных затрат.   -  person Dietrich Epp    schedule 07.02.2015


Ответы (3)


Взгляни на

http://www.realtimerendering.com/intersections.html

Много помощи в определении пересечений между различными видами геометрии

http://geomalgorithms.com/code.html также имеет некоторые функции C++, одна из которых служит вашей цели

person parapura rajkumar    schedule 06.02.2015
comment
Из этих источников я могу получить тот же учебник, на который я ссылался в своем посте. Кажется, что-то не так с моей текущей реализацией? - person Yattabyte; 07.02.2015

Поскольку у вас, кажется, есть проблемы с построением ваших лучей, вот как я бы это сделал. Это не было проверено напрямую. Вы можете сделать это так, убедившись, что все векторы находятся в одном пространстве. Если вы используете несколько матриц модели (или их стопки), расчет необходимо повторить отдельно для каждой из них.

  1. используйте pos = gluUnproject(winx, winy, near, ...), чтобы получить положение координаты мыши на ближней плоскости в пространстве модели; near — это значение, присвоенное glFrustum() или gluPerspective()
  2. начало луча — это положение камеры в пространстве модели: rayorig = inv(modelmat) * camera_in_worldspace
  3. направление луча - это нормализованный вектор от положения от 1 до начала луча: raydir = normalize(pos - rayorig)

На связанном веб-сайте они используют две точки для луча и, похоже, не нормализуют вектор направления луча, поэтому это необязательно.

person rpress    schedule 07.02.2015
comment
Всякий раз, когда я использую функцию unproject, возвращаемые координаты совершенно неверны. Если я щелкну вершину с координатами (0, -180, 0), координаты моей мыши для луча изменятся на что-то вроде (-0,66, -2,01, 0 или 1). Эти координаты не имеют смысла, так как вершина имеет значение +x, а не отрицательное значение. Кроме того, что нормализует? У меня нет большого опыта работы с векторной логикой - person Yattabyte; 09.02.2015

Итак, это начало моего следа хлебных крошек.

У меня как-то возникли проблемы с типами данных QT для матриц и логикой, относящейся к матричным преобразованиям.

Эта конкретная проблема в этом вопросе возникла из-за того, что на самом деле не выполнялись какие-либо преобразования.

Шаги к решению этой проблемы были такими:

  • Преобразование координат мыши в пространство NDC (в диапазоне от -1 до 1: x/ширина экрана * 2 - 1, y - высота/высота * 2 - 1)
  • захват матрицы 4x4 для моей матрицы просмотра (может быть та, которая используется при рендеринге или пересчитывается)
  • В новом векторе он должен быть равен матрице обратного вида, умноженной на матрицу обратной проекции.

Чтобы построить луч, мне пришлось сделать следующее:

  • Возьмите ранее рассчитанное значение для матриц, которые были перемножены вместе. Это будет умножено на вектор 4 (массив из 4 точек), где он будет содержать ранее вычисленные координаты x и y, а также -1, затем +1.
  • Затем этот вектор будет разделен на значение последней точки всего вектора.
  • Создайте еще один вектор 4, такой же, как и предыдущий, но вместо -1 поставьте 1 .
  • Еще раз разделите это на его последнюю спотовую стоимость.

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

Я открыл серию вопросов (из-за большой неопределенности с моей серией проблем), так что части моей проблемы тоже пересекаются в них.

  • Здесь я узнал, что мне нужно учитывать высоту экрана для переключения начало оси Y для декартовой системы, поскольку в Windows ось Y начинается слева вверху. Кроме того, извлечение матриц было избыточным, но также и неправильным, поскольку они никогда не объявлялись должным образом.
  • Здесь я узнал, что unProject не работает, потому что я пытаясь получить модель и просмотреть матрицы с помощью функций OpenGL, но я никогда не устанавливал их в первую очередь, потому что я построил матрицы вручную. Я решил эту проблему в два раза: я сделал математику вручную и сделал все матрицы одного типа данных (раньше они были смешанными типами данных, что также приводило к проблемам).
  • И, наконец, здесь я узнал, что мой порядок операций немного отличается (нужно умножать матрицы на вектор, а не наоборот), что моя ближняя плоскость должна быть -1, а не 0, и что последнее значение вектора, которое будет умножено на матрицы (значение w), должно быть 1 .

Кредиты идут тем людям, которые помогли мне решить эти проблемы:

person Yattabyte    schedule 15.02.2015