Russian Qt Forum
Ноябрь 25, 2024, 14:07 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: [РЕШЕНО] получение координат точки на сфере  (Прочитано 18707 раз)
spirits25
Гость
« : Июнь 20, 2013, 17:25 »

Всем привет!

Есть сфера (QGLSceneNode), центр которой совпадает с центром всей сцены. Необходимо получить декартовые координаты точки, по которуй произведён клик мышью. Какой алгоритм используется? необходимо через registerObject регистрировать объект и при его сигнале clicked определять эти координаты, по которым произведён клик?

Я тут как в тёмном лесу=) Спасибо за любую помощь (ссылки, алгоритм, код).
« Последнее редактирование: Июнь 25, 2013, 15:52 от spirits25 » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #1 : Июнь 20, 2013, 18:06 »

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

- focal length в пикселях (не в мм) ИЛИ угол зрения. Ну и размеры рендеримой картинки (с этим проблем быть не должно)

Найдете - тогда поговорим
Записан
spirits25
Гость
« Ответ #2 : Июнь 21, 2013, 10:34 »

Нужно иметь

- focal length в пикселях (не в мм) ИЛИ угол зрения. Ну и размеры рендеримой картинки (с этим проблем быть не должно)

Найдете - тогда поговорим

Угол зрения есть - есть значение с которого "камера" смотрит на объект. А размеры картинки - это сфера, размер известен, но камера постоянно то приближается, то удаляется.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Июнь 21, 2013, 11:06 »

Угол зрения есть - есть значение с которого "камера" смотрит на объект. А размеры картинки - это сфера, размер известен, но камера постоянно то приближается, то удаляется.
Объект здесь совершенно ни при чем. Кликая на пиксель картинки (пусть даже пустой) Вы можете получить луч/вектор из камеры (0, 0, 0) в бесконечность. Он может пересекать сколько угодно объектов или ничего.
Цитировать
dir.x = pixel.x - center.x;   // X камеры слева направо
dir.y = center.y - pixel.y;   // Y камеры снизу вверх, а у пикселей наоборот
dir.z = -focal_length_pixels;  // Z камеры "на нас" (правая тройка)
Вот этот focal_length_pixels - параметр перспективной камеры который должен быть так или иначе задан. Например угол зрения alpha = 28 градусов по горизонтали, тогда
Цитировать
focal_length_pixels = image_width / 2 / tan(alpha * M_PI / 180 / 2);
Ну или image_height если по вертикали. Или может задаваться просто коэффициентои K, тогда
Цитировать
focal_length_pixels = image_width * K;
Как там в крутых классах - не знаю, там умудряются задрочить простейшие вещи  Плачущий Но то что этот параметр есть (или вычисляется из других) - это стопудово, без него перспективной камеры не существует.
Записан
spirits25
Гость
« Ответ #4 : Июнь 21, 2013, 11:23 »

Здесь (в Qt3D) у класса QGLView есть метод camera(), который возвращает объект камеры QGLCamera. Она смотрит в центр координат (где у меня и центр сферы).

У объекта камеры есть метод eye, который возвращает QVector3D
Цитировать
This property holds the position of the viewer's eye. The default value is (0, 0, 10).
По этому методу и определяется положение камеры относительно центра координат. Например, имею QVector3D(0, 0, 10), немного смещаю камеру - получаю QVector3D(-3.39115, -0.237631, 9.40444). Из этого я и высчитываю на какие координаты моей сферы в данный момент смотрит камера. Это те данные?

Но я всё же не понимаю, что такое image_width/image_height. - это просто сумма всех изображений на сфере (в пикселях)? Если да, то я их могу посчитать для каждой ситуации (это значение меняется при приближении и удалении камеры).
Записан
spirits25
Гость
« Ответ #5 : Июнь 21, 2013, 11:40 »

Ещё с перспективой связан метод viewSize(), который соответственно возвращает размер области, которая в данный момент отображена (вмещается в обзор камеры).

Вся моя проблема в том, что я не знаю как привязать клик мышью и получить координаты пересечения этого клика с объектом.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Июнь 21, 2013, 12:21 »

Просто сердце кровью обливается глядя как Вы неумело насилуете 3D  Плачущий  Ну вот Вы видели что футболиста могут показывать крупным планом (как этот дятел по мячику бьет) - но ведь камера на поле не выезжает. Просто маленький угол зрения (большой focal length, больше расстояние от пленки до затвора). А др камера может показать все поле (большой угол зрения).

У объекта камеры есть метод eye, который возвращает QVector3D
Цитировать
This property holds the position of the viewer's eye. The default value is (0, 0, 10).
По этому методу и определяется положение камеры относительно центра координат. Например, имею QVector3D(0, 0, 10), немного смещаю камеру - получаю QVector3D(-3.39115, -0.237631, 9.40444). Из этого я и высчитываю на какие координаты моей сферы в данный момент смотрит камера. Это те данные?
Это позиция/вращение самой камеры в мире. Получив вектор в координатах камеры мы можем перевести его в мир (если нужно, обычно нет). Тогда используются те данные что Вы говорите

Ещё с перспективой связан метод viewSize(), который соответственно возвращает размер области, которая в данный момент отображена (вмещается в обзор камеры).
Ищите что-то типа fieldOfView
Записан
spirits25
Гость
« Ответ #7 : Июнь 21, 2013, 16:15 »

Я, наверное, неправильно выразился или неверно написал. Вот часть кода, которая отвечает за изменение масштаба (или как это правильно назвать):
Код:
    float fov = camera()->fieldOfView();
    if (fov != 0.0f)
        camera()->setFieldOfView(2*scale);
    else
        camera()->setViewSize(scale2F);
Сам его не придумывал, взял из документации и с вашими словами он вроде как совпадает.

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

Спасибо за советы, сейчас буду копать в направленную сторону=)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Июнь 21, 2013, 17:07 »

Это я использую, я не знаю как рассчитать куда именно мышка кликает.
Вы можете найти вектор в координатах камеры как в посте #3 (размеры рендеримой картинки известны, пксель куда кликнули тоже). Помножив вектор на обратную матрицу камеры Вы получите вектор в мире (хотя обычно удобнее все считать в камере)
Записан
spirits25
Гость
« Ответ #9 : Июнь 24, 2013, 10:42 »

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

И после спроецировать с плоскости на сферу (пересчитать координаты)? Ведь так найдётся точка на плоскости, касательной к сфере в точке с координатами, куда в данный момент смотрит камера?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Июнь 24, 2013, 10:51 »

И после спроецировать с плоскости на сферу (пересчитать координаты)? Ведь так найдётся точка на плоскости, касательной к сфере в точке с координатами, куда в данный момент смотрит камера?
Нет. Если хотите расскажу "основы", а то сейчас трудности с взаимопониманием  Улыбающийся
Записан
spirits25
Гость
« Ответ #11 : Июнь 24, 2013, 11:07 »

Нет. Если хотите расскажу "основы", а то сейчас трудности с взаимопониманием  Улыбающийся

Думаю было бы не плохо=)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #12 : Июнь 24, 2013, 11:45 »

Базовые понятия

1) "Система координат". Для простоты полагаем что это 3 взаимо-перпендикулярные оси единичной длины. Наиболее популярное направление осей см выше, но может быть любым, напр autodesk направил Z вверх (и отлично себя чувствует). Мировая система координат - та в которой меряются все остальные. Все исходные координаты (читаемые из файла) "в мире". Координаты и вектора могут быть переведены из мира в систему координат камеры и обратно домножением на прямую/обратную матрицу камеры. В системе координат камеры центр (0, 0, 0)  - в мире это соответствует точке где стоит камера, ну для примера (100, 200, 5). Все эти многочисленные параметры типа upVector, eyeDir - это всего лишь способы задания матрицы камеры, т.е. ее позиции в мире и направлений осей.

2) "Перспектива". Камера смотрит в центр рендеримого экрана. Луч камера-пиксель определяет что будет видно в этом пикселе (что он пересекает). При этом необходимо так знать на каком расстоянии камера от центра экрана, иначе нет однозначности "какой луч для этого пикселя". Как говорилось выше этот параметр задается всяко-разно, часто через угол зрения.

Теперь Ваша задача.
Есть сфера (QGLSceneNode), центр которой совпадает с центром всей сцены. Необходимо получить декартовые координаты точки, по которуй произведён клик мышью.
Кликнув в пиксель Вы находите данный луч/вектор (не точку) см посте #3. Этот вектор в координатах камеры. Нормируете его и домножаете на радиус Вашей сферы - получили точку где луч пересек сферу. Переводите ее в мир (если надо). Voila

 
Записан
spirits25
Гость
« Ответ #13 : Июнь 24, 2013, 12:37 »

Кликнув в пиксель Вы находите данный луч/вектор (не точку) см посте #3. Этот вектор в координатах камеры.

Код:
void EarthView::mouseDoubleClickEvent(QMouseEvent *e)
{
    QVector3D pick = mapPoint(e->pos());
...
Камера находится на расстоянии 10 от центра координат.
Получаю примерно такой вектор в координатах камеры QVector3D(0.0935829, -0.0614973, -5). Это тот самый "данный луч/вектор".

Нормируете его и домножаете на радиус Вашей сферы - получили точку где луч пересек сферу.

Диаметр сферы - 1. То есть нормирую и домножаю на 0.5.
Код:
pick.normalized() * 0.5
Насколько я понимаю, по этим значениям невозможно понять пересеклась сфера или нет, случай "промаха" нужно отбрасывать заранее (не проблема).

Переводите ее в мир (если надо). Voila
Тут я не понял, на что именно нужно домножить? на projectionmatrix ( http://qt.developpez.com/doc/5.0-snapshot/qglcamera/#projectionmatrix )?
« Последнее редактирование: Июнь 24, 2013, 12:45 от spirits25 » Записан
spirits25
Гость
« Ответ #14 : Июнь 24, 2013, 17:07 »

Вот с помощью такого кода я могу найти расстояние от камеры до точки пересечения со сферой:

Код:
// длина вектора
qreal norm(QVector3D v)
{
  return sqrt(v.x()*v.x()+v.y()*v.y()+v.z()*v.z());
}

// скалярное произведение 2х векторов
qreal sprod(QVector3D v1, QVector3D v2)
{
  return v1.x()*v2.x()+v1.y()*v2.y()+v1.z()*v2.z();
}

// знак числа
// x>0 : 1
// x=0 : 0
// x<0 : -1
int Sign(float x)
{
  return (x>0)-(x<0);
}

/*
 *p  - начальная точка луча
 *l - направляющий вектор луча, необяз. единичный
 *c - центр сферы
 *r - радиус сферы
 */
float Ray2Sphere(QVector3D p, QVector3D l, QVector3D c, float r)
{
  // квадрат радиуса
  r*=r;
  // квадрат расстояния от точки до центра сферы
  float d=qPow(norm(c-p),2);
  // проекция центра сферы на луч
  float s=sprod(c-p,l)/norm(l);
  if(d>r && s<0) // точка снаружи сферы и луч направлен от сферы
    return -1; // нет пересечения
  // квадрат расстояния от прямой до центра сферы по теореме Пифагора
  float h=d-s*s;
  if(h>r) // луч не пересекает сферу
    return -1;
  return s+sqrt(r-h)*Sign(r-d); // расстояние до пересечения
}

То есть я знаю точку камеры, знаю направление и знаю расстояние. Можно посчитать саму точку (формулу ещё не искал).
В этом решении есть какие-то косяки?
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.055 секунд. Запросов: 23.