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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Billboard  (Прочитано 7011 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Июль 31, 2012, 10:46 »

Добрый день

Есть прямоугольник заданный угловыми точками QVector3D p[4]. Дана точка цели QVeсtor3D target. Надо повернуть прямоугольник мордой на цель: центр прямоугольника остается на своем месте, а угловые точки пересчитываются так чтобы вектор центр-цель был перпедикулярен плоскости прямоугольника. Ну как бы "радар отслеживает цель"

Спасибо
Записан
sergey_ulyanov
Гость
« Ответ #1 : Июль 31, 2012, 14:01 »

Код:
//4 точки прямоугольника
QVector3d vertex0, vertex1, vertex2, vertex3;

// Точка цели
QVector3d target;

// Нормаль к плоскости прямоугольника
QVector3d normal = QVector3D::crossProduct(vertex2 - vertex0, vertex1 - vertex0).normalized();

// Центр прямоугольника
QVector3d center = (vertex0 + vertex1 + vertex2 + vertex3) / 4;

// Направление из центра прямоугольника на цель
QVector3d eye = (target - center).normalized();

// Направление вектора "up"
// Определяется по линии проходящей через середину "верхнего" ребра и центр прямоугольника
// Здесь ребро vertex0-vertex1 приведено для примера
QVector3d up = ((vertex0 + vertex1) / 2 - center).normalized();

// Итоговая матрица поворота на цель
QMatrix4x4 rot;
rot.lookAt(eye, center, up);
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Июль 31, 2012, 16:05 »

Код:
// Итоговая матрица поворота на цель
QMatrix4x4 rot;
rot.lookAt(eye, center, up);
Так что-то не выходит, тестовый примерчик (аттач) печатает явно не то. Если это я где-то насвистел - скажите.

Спасибо
Записан
sergey_ulyanov
Гость
« Ответ #3 : Август 01, 2012, 10:00 »

Код
C++ (Qt)
void Transform(QVector3D p[4], const QVector3D &target)
{
   QVector3D normal = QVector3D::crossProduct(p[2] - p[0], p[1] - p[0]).normalized();
   QVector3D center = (p[0] + p[1] + p[2] + p[3]) / 4;
   QVector3D eye    = (target - center).normalized();
   double    theta  = acos(QVector3D::dotProduct(normal, eye));
 
   QMatrix4x4 translateToOrigin;
   translateToOrigin.translate(-center);
 
   QMatrix4x4 lookAtTarget;
   lookAtTarget.rotate(theta * (180.0 / M_PI), QVector3D::crossProduct(normal, eye));
 
   QMatrix4x4 translateToCenter;
   translateToCenter.translate(center);
 
   QMatrix4x4 t = translateToCenter * lookAtTarget * translateToOrigin;
 
   for (uint i = 0; i < 4; i++) {
       p[i] = t.map(p[i]);
   }
}
 
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Август 01, 2012, 20:19 »

Так все гуд, спасибо. Только нормаль надо взять наоборот (правая тройка, идем по часовой, должно быть (0, 0, -1)).
Я попробовал сделать по-другому (аттач), получается та же матрица. Но не могу понять почему надо transpose, наверное они как-то строки со столбцами замутили.
Записан
sergey_ulyanov
Гость
« Ответ #5 : Август 01, 2012, 20:57 »

Цитировать
Так все гуд, спасибо. Только нормаль надо взять наоборот (правая тройка, идем по часовой, должно быть (0, 0, -1)).
Вопрос правильности выбора нормали - условный. Все зависит в какой последовательности заданы точки контура и от априорных данных о "лицевой стороне".
Цитировать
Я попробовал сделать по-другому (аттач), получается та же матрица. Но не могу понять почему надо transpose, наверное они как-то строки со столбцами замутили.
В предложенном мной варианте делается всего один поворот вокруг вектора нормального к плоскости нормаль-цель на угол между этими двумя векторами. В приведенном вами варианте выполняется 2 последовательных поворота. transpose вообще говоря неправильно, вернее было бы inverted, просто матрица поворота ортогональна и поэтому для нее это эквивалентно. Обращение же матрицы необходимо здесь т.к. повороты получены для вектора направления на цель, а не для нормали плоскости.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Август 02, 2012, 13:05 »

В предложенном мной варианте делается всего один поворот вокруг вектора нормального к плоскости нормаль-цель на угол между этими двумя векторами. В приведенном вами варианте выполняется 2 последовательных поворота.
Один зато какой. Вызываете acos, который rotate опять переводит в cos. Синус у Вас тоже пракически посчитан, но rotate его опять считает. Так что с точки зрения оптимальности - спорно. Однако я вовсе не хочу доказать что "мой вариант лучше" - просто хочется понять как это получается. Когда разберусь - возможно буду пользоваться тем же rotate.

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

- умножение на матрицу M1 соответствует переводу точек из мировой системы координат в локальную, поэтому заполняем M1 по столбцам (обратная матрица)

- умножение на матрицу M2 = перевод точек из локальной в мировую, заполняем M2 по строкам (прямая матрица)

Если M2 получается из M1 вращением (а это так), то произведение M1 * M2 должно выполнить нужный поворот (без всяких transposed). Где ошибка?
Записан
sergey_ulyanov
Гость
« Ответ #7 : Август 02, 2012, 13:26 »

Цитировать
Когда разберусь - возможно буду пользоваться тем же rotate.
Rodrigues Rotation Formula

Цитировать
Конечно умножение на матрицу с нулевым смещением есть поворот
Неверно, у матрицы растяжения/сжатия тоже нулевое смещение
« Последнее редактирование: Август 02, 2012, 13:31 от sergey_ » Записан
sergey_ulyanov
Гость
« Ответ #8 : Август 02, 2012, 14:30 »

Цитировать
Если M2 получается из M1 вращением (а это так), то произведение M1 * M2 должно выполнить нужный поворот (без всяких transposed). Где ошибка?

Ну наверное нужно понять, что собой представляют матрицы M1 и M2 в вашем примере.
M1 - базис системы координат прямоугольника. Базисные вектора (записываются по столбцам матрицы):
ortX - нормаль к плоскости образованной вектором нормали прямоугольника и направлением из его центра на цель
ortZ1*ortX - дополнение до тройки векторов
ortZ1 - нормаль прямоугольника

M2 - базис системы требуемой системы
ortX - нормаль к плоскости образованной вектором нормали прямоугольника и направлением из его центра на цель
ortZ2*ortX - дополнение до тройки векторов
ortZ2 - направление из центра прямоугольника на цель

Первая ошибка - в матрице M2 вместо того, чтобы поставить базисные вектора по столбцам, вы ставите их по строкам (транспонируете).
Вторая ошибка - это порядок преобразования. Здесь была такая идея:
- перенести центр координат прямоугольника в начало мировых координат (матрица translateToOrigin)
- перейти к СК прямоугольника (матрица M1)
- выполнить переход к требуемому базису (матрица M2)
- вернуться обратно к исходному центру прямоугольника (матрица translateToCenter)

Итого T= translateToCenter * M2 * M1 * translateToOrigin;
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Август 02, 2012, 14:53 »

Здесь была такая идея:
- перенести центр координат прямоугольника в начало мировых координат (матрица translateToOrigin)
- перейти к СК прямоугольника (матрица M1)
- выполнить переход к требуемому базису (матрица M2)
- вернуться обратно к исходному центру прямоугольника (матрица translateToCenter)
Совершенно верно, именно так я и хотел. Наверно если аккуратно расписать матричное произведение то и получится формула товарища Родригеса. Предлагаю не тратить время на упоминания о том что надо отнять/добавить смещение, это очевидно

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

Итого T= translateToCenter * M2 * M1 * translateToOrigin;
Чего же это мы сразу (из мира) множимся на M2, которая есть новая (требуемая) СК?  Мы должны сначала соскочить в локальную (помножить на M1)

Подозреваю что QMatrix4x4 преобразует не так как я полагаю. Я рассчитываю что "матрица справа", и матрица записанная по строкам соответствует "из локальной в мир"
Записан
sergey_ulyanov
Гость
« Ответ #10 : Август 02, 2012, 15:04 »

Цитировать
Чего же это мы сразу (из мира) множимся на M2, которая есть новая (требуемая) СК?  Мы должны сначала соскочить в локальную (помножить на M1)

Непонимающий

Я же писал порядок преобразования:
Цитировать
Здесь была такая идея:
- перенести центр координат прямоугольника в начало мировых координат (матрица translateToOrigin)
- перейти к СК прямоугольника (матрица M1)
- выполнить переход к требуемому базису (матрица M2)
- вернуться обратно к исходному центру прямоугольника (матрица translateToCenter)

Порядок выполнения операций:

Цитировать
Итого T= translateToCenter * M2 * M1 * translateToOrigin;

1. translateToOrigin
2. M1
3. M2
4. translateToCenter

Множимся на M2 мы не из мира а из M1
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Август 02, 2012, 16:34 »

Цитировать
Итого T= translateToCenter * M2 * M1 * translateToOrigin;

1. translateToOrigin
2. M1
3. M2
4. translateToCenter

Множимся на M2 мы не из мира а из M1
А как же Вы заставите операторы выполняться справа налево  Непонимающий
Записан
sergey_ulyanov
Гость
« Ответ #12 : Август 02, 2012, 16:38 »

Цитировать
А как же Вы заставите операторы выполняться справа налево
Непонимающий
Зачем справа-налево?
u = T*v
T= translateToCenter * M2 * M1 * translateToOrigin
u = translateToCenter * M2 * M1 * translateToOrigin * v
что эквивалентно
u = (translateToCenter * (M2 * (M1 * (translateToOrigin * v))))
В линейной алгебре уж так принято)
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #13 : Август 02, 2012, 17:08 »

Зачем справа-налево?
u = T*v
T= translateToCenter * M2 * M1 * translateToOrigin
u = translateToCenter * M2 * M1 * translateToOrigin * v
что эквивалентно
u = (translateToCenter * (M2 * (M1 * (translateToOrigin * v))))
В линейной алгебре уж так принято)
Насколько мне известно

M = M1 * M2

Элементы новой матрицы M получаются как суммы произведений строк M1 на столбцы M2. О др правилах векторной алгебры я не слышал. То что Вы говорите понятно если бы матрица применялась "слева". Но ведь судя по исходникам не так
Код
C++ (Qt)
inline QVector3D operator*(const QMatrix4x4& matrix, const QVector3D& vector)
{
   qreal x, y, z, w;
...
       x = vector.x() * matrix.m[0][0] +
           vector.y() * matrix.m[1][0] +
           vector.z() * matrix.m[2][0] +
           matrix.m[3][0];
       y = vector.x() * matrix.m[0][1] +
           vector.y() * matrix.m[1][1] +
           vector.z() * matrix.m[2][1] +
           matrix.m[3][1];
       z = vector.x() * matrix.m[0][2] +
           vector.y() * matrix.m[1][2] +
           vector.z() * matrix.m[2][2] +
           matrix.m[3][2];
 
Я так вижу что вектор-строка множится на столбцы матрицы  Непонимающий
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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